【问题标题】:Microsoft.Owin.Security.OpenIdConnect with Azure Active Directory authentication ticket lifetimeMicrosoft.Owin.Security.OpenIdConnect 与 Azure Active Directory 身份验证票证生命周期
【发布时间】:2016-05-03 04:43:48
【问题描述】:

我正在构建一个多租户 Web 应用程序,该应用程序使用 Microsoft.Owin.Security.OpenIdConnect, Version=3.0.0.0 和带有 Microsoft.IdentityModel.Clients 的 Azure Active Directory 连接 Office 365 服务.ActiveDirectory,Version=2.19.0.0this sample 之后。

我们的 Web 应用客户端(用户代理)使用 asp.NET cookie 对我们的服务器进行身份验证,而我们的服务器和授权服务器(此处为 Azure AD)之间的身份验证是使用 OpenID 授权代码流进行的。

我们为 Asp.NET cookie 设置了 30 天的滑动到期期限。然而,即使在设置 UseTokenLifetime= true 时,我们仍然有一个来自权威服务器的短暂 AuthenticationTicket,它应该与两种身份验证机制的生命周期相匹配。

我们遇到的问题是:我们的最终用户必须经常重新登录(少于一小时)。那么问题来了,我们如何在这个 owin openidconnect 中间件中增加/更改身份验证票证的生命周期?

备注:我还发布了 a question 关于 ADAL 刷新令牌的使用。 据我们了解,这个问题只和认证有关。 access_tokenrefresh_token 的生命周期是由 ActiveDirectory 客户端管理的授权问题,与此问题无关。如果我错了,请纠正我。

Startup.Auth.cs

public partial class Startup
{
  public const string CookieName = ".AspNet.MyName";
  public const int DayExpireCookie = 30;

  public void ConfigureAuth(IAppBuilder app)
  {
   app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);

   var cookieAuthenticationOptions = new CookieAuthenticationOptions()
   {
       CookieName = CookieName,
       ExpireTimeSpan = TimeSpan.FromDays(DayExpireCookie),
       AuthenticationType = CookieAuthenticationDefaults.AuthenticationType,
       SlidingExpiration = true,
   };

   app.UseCookieAuthentication(cookieAuthenticationOptions);

   app.UseOpenIdConnectAuthentication(
       new OpenIdConnectAuthenticationOptions
       {
           ClientId = SettingsHelper.ClientId,
           Authority = SettingsHelper.Authority,
           ClientSecret = SettingsHelper.AppKey,
           UseTokenLifetime = true,
           TokenValidationParameters = new System.IdentityModel.Tokens.TokenValidationParameters
           {
               ValidateIssuer = false
           },

           Notifications = new OpenIdConnectAuthenticationNotifications()
           {
               // If there is a code in the OpenID Connect response, redeem it for an access token and refresh token, and store those away. 
               AuthorizationCodeReceived = (context) =>
               {
                   var code = context.Code;
                   string tenantID = context.AuthenticationTicket.Identity.FindFirst("http://schemas.microsoft.com/identity/claims/tenantid").Value;
                   string signInUserId = context.AuthenticationTicket.Identity.FindFirst(ClaimTypes.NameIdentifier).Value;
                   AuthenticationContext authContext = new AuthenticationContext(string.Format("{0}/{1}", SettingsHelper.AuthorizationUri, tenantID), new ADALTokenCache(signInUserId));
                   ClientCredential credential = new ClientCredential(SettingsHelper.ClientId, SettingsHelper.AppKey);
                   // Get the access token for AAD Graph. Doing this will also initialize the token cache associated with the authentication context
                   // In theory, you could acquire token for any service your application has access to here so that you can initialize the token cache
                   Uri redirectUri = new Uri(HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Path));
                   AuthenticationResult result = authContext.AcquireTokenByAuthorizationCode(code, redirectUri, credential, SettingsHelper.AADGraphResourceId);
                   return Task.FromResult(0);
               },

               RedirectToIdentityProvider = (RedirectToIdentityProviderNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> context) =>
               {
                   string appBaseUrl = context.Request.Scheme + "://" + context.Request.Host + context.Request.PathBase;
                   context.ProtocolMessage.RedirectUri = appBaseUrl + SettingsHelper.LoginRedirectRelativeUri;
                   context.ProtocolMessage.PostLogoutRedirectUri = appBaseUrl + SettingsHelper.LogoutRedirectRelativeUri;
                   return Task.FromResult(0);
               },
               AuthenticationFailed = (context) =>
               {
                   context.HandleResponse();
                   return Task.FromResult(0);
               }
           }
       });
  }
}

账户管理员

public class AccountController : Controller
{

     public void SignIn()
     {
         var dateTimeOffset = DateTimeOffset.UtcNow;
         var authenticationProperties = new AuthenticationProperties
         {
             AllowRefresh = true,
             IssuedUtc = dateTimeOffset,
             ExpiresUtc = dateTimeOffset.AddDays(Startup.DayExpireCookie -1),
             RedirectUri = SettingsHelper.LoginRedirectRelativeUri, IsPersistent = true
         };
         HttpContext.GetOwinContext()
             .Authentication.Challenge(authenticationProperties,OpenIdConnectAuthenticationDefaults.AuthenticationType, CookieAuthenticationDefaults.AuthenticationType);
     }

     public void SignOut()
     {
         HttpContext.GetOwinContext().Authentication.SignOut(
             new AuthenticationProperties { RedirectUri = SettingsHelper.LogoutRedirectRelativeUri,  },
             OpenIdConnectAuthenticationDefaults.AuthenticationType, CookieAuthenticationDefaults.AuthenticationType);
     }
 }

【问题讨论】:

  • 注意 UseTokenLifetime 会导致 OIDC 中间件覆盖 cookie 中间件超时,而不是相反。
  • 令牌的生命周期由 AAD 控制,而不是您在自己的代码中执行的任何操作。 stackoverflow.com/questions/22043128/…
  • 谢谢。您的参考是处理 access_tokenrefresh_token 的生命周期,但现在,一小时后我无法通过控制器的 [Authorize] 属性,所以我不知道我怎么能要求一个新的令牌。您确定 access_token 的生命周期是 401 unauthorize 响应的罪魁祸首吗?它看起来与我的其他问题有关stackoverflow.com/questions/35017681/…
  • 我注意到您设置了:ValidateIssuer = false。对于为多租户提供服务并使用相同签名令牌的 IDP,您可能正在接受来自另一个租户的令牌。
  • 还要注意 Claim.FindFirst 可以返回 null。

标签: owin office365 azure-active-directory openid-connect adal


【解决方案1】:

其实, 我需要设置UseTokenLifetime = false。 实际上,UseTokenLifetime = true 将 Asp.NET cookie 中的内部票证更改为默认生命周期 access_token,即一小时。 @Tratcher 的 cmets 是真实的,但误导了我……是的,access_token 的生命周期由 Azure AD 控制,对此我无能为力。但是,我们使用 ADAL.NET 实现了refresh_token 管理,因此可以将 Microsoft 身份服务器的身份验证/授权保持超过一小时。设置UseTokenLifetTime = false 并在我的客户端应用程序和我的服务器之间使用 15 天滑动到期时间的 cookie 身份验证现在就像一个魅力。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-01-11
    • 1970-01-01
    • 1970-01-01
    • 2016-12-15
    • 2016-01-12
    • 2018-03-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多