我在Web应用程序中使用OAuth和O365单点登录。当应用程序启动时,提示用户使用SSO登录。获取令牌有效,并且登录成功。用户登录后,他们将使用图客户端与Graph进行交互,该图客户端将建立一个ConfidentialClientApplication并访问会话令牌存储。那也很好。但是在45分钟到一个小时后,该客户端呼叫失败。令牌存储中有一个对象,但是当CCA调用GetAccountsAsync()时,它始终返回0,因此AcquireTokenSilentAsync失败。我是否未能在令牌存储中存储一些相关信息?我在这里做错什么以及如何解决?我尝试重新发出挑战,然后再次访问令牌存储,但是结果是一样的:尽管存储中有对象,但GetAccountsAsync返回0个帐户。
我想知道这是否与我一直基于的TokenStore示例有关。我曾尝试将令牌存储在Session和Cache中,并且它们都在用户首次通过身份验证时起作用,但是似乎在某些时候发生了使令牌在后续请求中失效的情况。
从Startup.Auth.cs:
public void ConfigureAuth(IAppBuilder app)
{
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions() { CookieSecure = CookieSecureOption.Never, CookieName = "AppCookie", ExpireTimeSpan = TimeSpan.FromDays(7) });
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
ClientId = clientId,
Authority = authority,
PostLogoutRedirectUri = postLogoutRedirectUri,
ResponseType = OpenIdConnectResponseType.CodeIdToken,
TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
{
ValidateIssuer = false,
RoleClaimType = "roles",
NameClaimType = "upn"
},
UseTokenLifetime = true,
RedirectUri = postLogoutRedirectUri,
Scope = "openid profile offline_access " + graphScopes,
Notifications = new OpenIdConnectAuthenticationNotifications()
{
RedirectToIdentityProvider = (context) =>
{
string appBaseUrl = context.Request.Scheme + "://" + context.Request.Host + context.Request.PathBase;
context.ProtocolMessage.RedirectUri = appBaseUrl;
context.ProtocolMessage.PostLogoutRedirectUri = appBaseUrl;
return Task.FromResult(0);
},
AuthorizationCodeReceived = OnAuthorization,
AuthenticationFailed = OnAuthenticationFailed
}
});
}
private Task OnAuthenticationFailed(AuthenticationFailedNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> context)
{
context.OwinContext.Response.Redirect("/Home/Error?message=" + context.Exception.Message);
return Task.FromResult(0);
}
private async Task OnAuthorization(AuthorizationCodeReceivedNotification context)
{
var code = context.Code;
string signedInUserID = context.AuthenticationTicket.Identity.FindFirst(ClaimTypes.NameIdentifier).Value;
SessionTokenStore tokenStore = new SessionTokenStore(signedInUserID, context.OwinContext.Environment["System.Web.HttpContextBase"] as HttpContextBase);
ConfidentialClientApplication cca = new ConfidentialClientApplication(clientId, postLogoutRedirectUri, new ClientCredential(appKey), tokenStore.GetMsalCacheInstance(), null);
var accounts = await cca.GetAccountsAsync();
try
{
AuthenticationResult result = await cca.AcquireTokenByAuthorizationCodeAsync(code, graphScopes.Split(' '));
}
catch (MsalException ex)
{
string message = "AcquireTokenByAuthorizationCodeAsync threw an exception";
context.HandleResponse();
context.Response.Redirect($"/Home/Error?message={message}&debug={ex.Message}");
}
catch (Microsoft.Graph.ServiceException ex)
{
string message = "GetUserDetailsAsync threw an exception";
context.HandleResponse();
context.Response.Redirect($"/Home/Error?message={message}&debug={ex.Message}");
}
catch (Exception ex)
{
throw ex;
}
}
获取Graph客户端:
private static GraphServiceClient GetAuthenticatedClient()
{
try
{
return new GraphServiceClient(
new DelegateAuthenticationProvider(
async (requestMessage) =>
{
string signedInUserID = ClaimsPrincipal.Current.FindFirst(ClaimTypes.NameIdentifier).Value;
SessionTokenStore tokenStore = new SessionTokenStore(signedInUserID, new HttpContextWrapper(HttpContext.Current));
ConfidentialClientApplication cca = new ConfidentialClientApplication(appId, redirectUri.ToString(), new ClientCredential(appSecret), tokenStore.GetMsalCacheInstance(), null);
var accounts = await cca.GetAccountsAsync();
try
{
var result = await cca.AcquireTokenSilentAsync(graphScopes.Split(' '), accounts.FirstOrDefault(), null, true);
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
}
catch (MsalUiRequiredException ex)
{
if (ex.ErrorCode == MsalUiRequiredException.UserNullError)
{
new HttpContextWrapper(HttpContext.Current).GetOwinContext().Authentication.Challenge(
new AuthenticationProperties { RedirectUri = redirectUri }, OpenIdConnectAuthenticationDefaults.AuthenticationType);
var account = await cca.GetAccountAsync(signedInUserID);
var result = await cca.AcquireTokenSilentAsync(graphScopes.Split(' '), account, null, true);
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
}
else
{
throw ex;
}
}
}));
}
catch (Exception e)
{
throw e;
}
}