C# 当ajax调用失败时在后端续订访问令牌
我们有一个ASP.NETMVC5Web应用程序,我们使用AngularJS从MVC控制器(而不是APIController)获取数据。其身份验证使用cookie身份验证链接到Azure AD,默认过期时间为1小时后 该应用程序是一个水疗中心。用户登录后,不会导航到其他页面,只使用ajax($http)调用 到目前为止,我们在Startup.Configuration()中扩展了RedirectToIdentityProvider方法,以识别ajax调用,并在令牌过期时向客户端返回错误403。这样,我们就避免了重定向到authority页面并得到CORS错误 此外,我们在同一类的C# 当ajax调用失败时在后端续订访问令牌,c#,angularjs,ajax,asp.net-mvc,azure-active-directory,C#,Angularjs,Ajax,Asp.net Mvc,Azure Active Directory,我们有一个ASP.NETMVC5Web应用程序,我们使用AngularJS从MVC控制器(而不是APIController)获取数据。其身份验证使用cookie身份验证链接到Azure AD,默认过期时间为1小时后 该应用程序是一个水疗中心。用户登录后,不会导航到其他页面,只使用ajax($http)调用 到目前为止,我们在Startup.Configuration()中扩展了RedirectToIdentityProvider方法,以识别ajax调用,并在令牌过期时向客户端返回错误403。这样
AuthorizationCodeReceived
中实现了持久令牌缓存助手TokenCache
(命名空间Microsoft.IdentityModel.Clients.ActiveDirectory
)
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
ClientId = ConfigurationHelper.ClientId,
Authority = ConfigurationHelper.AzureAdAuthorizationUri,
TokenValidationParameters = new System.IdentityModel.Tokens.TokenValidationParameters
{
ValidateIssuer = true
},
Notifications = new OpenIdConnectAuthenticationNotifications()
{
AuthorizationCodeReceived = (context) =>
{
var code = context.Code;
ClientCredential credential = new ClientCredential(ConfigurationHelper.ClientId, ConfigurationHelper.AppKey);
String UserObjectId = context.AuthenticationTicket.Identity.FindFirst(ClaimTypes.NameIdentifier).Value;
AuthenticationContext authContext = new AuthenticationContext(ConfigurationHelper.AzureAdAuthorizationUri, new InMemoryTokenCache(UserObjectId));
AuthenticationResult result = authContext.AcquireTokenByAuthorizationCode(code, new Uri(HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Path)), credential, ConfigurationHelper.AzureAdGraphResourceUri);
return Task.FromResult(0);
},
RedirectToIdentityProvider = (context) =>
{
if (IsAjaxRequest(context.Request))
{
context.Response.StatusCode = 401; // for web API only!
context.Response.Headers.Remove("Set-Cookie");
context.State = NotificationResultState.HandledResponse;
}
else
{
string appBaseUrl = context.Request.Scheme + "://" + context.Request.Host + context.Request.PathBase;
context.ProtocolMessage.RedirectUri = appBaseUrl + "/" + context.Request.QueryString;
context.ProtocolMessage.PostLogoutRedirectUri = appBaseUrl;
}
return Task.FromResult(0);
},
AuthenticationFailed = (context) =>
{
// Suppress the exception
context.HandleResponse();
return Task.FromResult(0);
}
}
});
}
是我们对InMemoryTokenCache
TokenCache
是一个识别ajax调用的函数。其余的都是ASP.NETMVC5模板中的标准配置IsAjaxRequest
我们的问题是,当用户访问令牌过期时,我们希望刷新它并继续运行,而不将用户重定向到登录屏幕或将403返回到客户端。我们应该在哪里以及如何做到这一点 解决此问题的一种方法是在令牌过期之前刷新它。 在我的例子中,我的应用程序由Node.js服务器提供的许多单页组成。 登录后,我将
token.expires\u存储在服务器端可访问的cookie中
当用户导航或点击F5刷新页面时,服务器使用tokenExpiresIn
初始化客户端上下文。
如果令牌在100分钟后过期,它将在90分钟后自动刷新
示例代码
angular.module('app').run(function() {
var tokenExpiresIn = context['tokenExpiresIn'];
if (tokenExpiresIn) {
refreshToken(tokenExpiresIn);
}
// Automatically refresh token after a delay
function refreshToken(delay) {
$log.debug('Token will be refreshed in ' + delay + ' ms');
$timeout(function () {
AuthenticationService.refreshToken().then(
function (token) {
// Token refresh successful
// Broadcast event so that anyone can react if necessary
$rootScope.$broadcast(AuthenticationService.Events.REFRESH_TOKEN, token);
// Refresh token again after this one expires
refreshToken(token.expires_in * 1000 * (90/100);
}, function (error) {
// Token is invalid, force logout
AuthenticationService.logout();
});
}, delay);
}
});
另一种方法是使用身份验证拦截器
angular
.module('app')
.factory('authenticationHTTP401Interceptor', authenticationHTTP401Interceptor)
// Intercept 401 Unauthorized http response from Backend
authenticationHTTP401Interceptor.$inject = ['$q'];
function moAuthenticationHTTP401Interceptor($q) {
return {
responseError: function(rejection) {
if (rejection.status === 401
&& rejection.config.url
&& rejection.config.url.indexOf(context.BACKEND_BASE_URL') === 0
&& rejection.headers("WWW-Authenticate")
&& rejection.headers("WWW-Authenticate").indexOf('error="invalid_token"') !== -1
&& rejection.headers("WWW-Authenticate").indexOf('error_description="The access token expired"') !== -1
)
// Or using a RegExp
// if (rejection.status === 401
// && /invalid_token.*The access token expired/.test(rejection.headers("WWW-Authenticate"))
// )
{
// Refresh token here
// Display an overlay while doing it if necessary
}
return $q.reject(rejection);
}
};
}
来源:这是一个选择,但理论上说我不应该这样做。刷新令牌仅用于获取访问令牌,并且仅当用户在稍后到期后请求某些内容时才使用。我添加了另一个解决方案,希望能有所帮助;)