Angular刷新令牌授权问题
Angular Refresh Token Authorization Issue
我有一个 Angular client.I 使用 Asp.Net WebApi 创建了一个不记名令牌授权系统。它使用指定时间较短的访问令牌和指定时间较长的刷新令牌。当访问令牌过期并且向具有多个 $http 请求的页面发出请求时,我遇到了问题。我设置了一个用于检索数据的服务,如果第一个响应返回 401,它会从刷新令牌服务器获取一个新令牌,然后对数据发出第二个请求。发生的情况是两个安全请求几乎同时触发,它们都失败了 401,它们都必须获得一个新令牌,并且第一个令牌检索被第二个无效。
我突然想到了两个修复程序。 1.) 将调用链接到我的数据服务。 2)以页面对所有数据发出一次请求的方式安排我的请求。我不打算详细说明为什么这两种方法是不可接受的,我相信你知道为什么。
我考虑过 "locking" 向令牌服务器请求,而其他请求正在进行中,或者为令牌请求设置队列服务,我显然是在努力避免瓶颈,同时保持我的完整性承诺链。
我相信其他人也经历过这种情况,只是想知道其他人采取了什么方法。
提前致谢!
您是否在 angular app.config 方法中覆盖了 $httpProvider?
通过使用$httpProvider.interceptors.push(<Your auth interceptor>);
如果没有,拦截器将监控您的 angular 应用发出的所有请求,并使用下面的 "optional functions" 处理它们。
您将建立一个工厂来处理所有事情,例如下面的裸机。
这基本上一次接受一个请求。所以对于并发请求问题,第一个请求会通过工厂请求函数并设置headers。然后将发出请求并点击响应函数。如果响应 returns 一个错误,工厂响应错误函数将被调用,如果将评估 401 的状态代码,您可以实现一种方法来请求新的持有者令牌。完成后,第二个请求将发送,新的不记名令牌已经设置好,您应该可以开始了。
angular.module('authInterceptor', []).factory('Interceptor', Interceptor);
function Interceptor($q, $cookie){
var factory = {
response: response,
responseError: responseError,
request: request,
};
//////////////////
//This will setup the http request
//Since your using a bearer token and refresh token you will want to add the bearer token the the header of all the requests
function request(config) {
//Set config.headers to existing headers or if none exists set it to an empty object
config.headers = config.headers || {};
//Grab you auth data from storage
//I usually store the object from the /token request in $cookie
var authData = $cookies.getObject("authData");
//If authData exists set it as a Authorization header
if (authData) {
config.headers.Authorization = "Bearer " + authData.access_token;
}
}
function response(response) {
return response || $q.when(response);
}
//Where the 401 magic happens
//If your rejection status is a 401(UnAuthorized)
//You want to request a new token from the authorization service
function responseError(rejection) {
var deferred = $q.defer();
if (rejection.status === 401) {
//You need to manually inject services or factories since your in the .config method
var Authentication = $injector.get("Authentication");
//I usually set up a Authentication Service to do the dirty work so the interceptor doesnt get bloated with code
//See below for reissue token
Authentication.reissueToken()
.then(function () {
//Valid grant
}, function (err) {
//Invalid grant
});
//When this get his the original $http request that failed will get resent to the server
return deferred.promise;
}
return $q.reject(rejection);
}
}
/*Reissue token
* Grabs the authData from storage, using the bearer token make a request to the token endpoint
* If the refresh token hasnt expired the success will send back a new bearer token.
* Update the auth cookie with the new token object
* If the refresh token has expired the request will result in an invalid_grant request will
* be rejected, user must log in again*/
function reissueToken() {
var deferred = $q.defer();
var authData = $cookies.getObject("authData");
if (authData) {
var token = authData.refresh_token;
var data = "grant_type=refresh_token&refresh_token=" + token + "&client_id=" + clientId;
$http.post("/token", data)
.success(function (newToken) {
//Update wherever you store the authorization data
}).error(function (err, status) {
deferred.reject();
});
} else {
deferred.reject();
}
return deferred.promise;
}
你可以阅读更多here ctrl + f for interceptor
我有一个 Angular client.I 使用 Asp.Net WebApi 创建了一个不记名令牌授权系统。它使用指定时间较短的访问令牌和指定时间较长的刷新令牌。当访问令牌过期并且向具有多个 $http 请求的页面发出请求时,我遇到了问题。我设置了一个用于检索数据的服务,如果第一个响应返回 401,它会从刷新令牌服务器获取一个新令牌,然后对数据发出第二个请求。发生的情况是两个安全请求几乎同时触发,它们都失败了 401,它们都必须获得一个新令牌,并且第一个令牌检索被第二个无效。
我突然想到了两个修复程序。 1.) 将调用链接到我的数据服务。 2)以页面对所有数据发出一次请求的方式安排我的请求。我不打算详细说明为什么这两种方法是不可接受的,我相信你知道为什么。
我考虑过 "locking" 向令牌服务器请求,而其他请求正在进行中,或者为令牌请求设置队列服务,我显然是在努力避免瓶颈,同时保持我的完整性承诺链。
我相信其他人也经历过这种情况,只是想知道其他人采取了什么方法。
提前致谢!
您是否在 angular app.config 方法中覆盖了 $httpProvider?
通过使用$httpProvider.interceptors.push(<Your auth interceptor>);
如果没有,拦截器将监控您的 angular 应用发出的所有请求,并使用下面的 "optional functions" 处理它们。
您将建立一个工厂来处理所有事情,例如下面的裸机。 这基本上一次接受一个请求。所以对于并发请求问题,第一个请求会通过工厂请求函数并设置headers。然后将发出请求并点击响应函数。如果响应 returns 一个错误,工厂响应错误函数将被调用,如果将评估 401 的状态代码,您可以实现一种方法来请求新的持有者令牌。完成后,第二个请求将发送,新的不记名令牌已经设置好,您应该可以开始了。
angular.module('authInterceptor', []).factory('Interceptor', Interceptor);
function Interceptor($q, $cookie){
var factory = {
response: response,
responseError: responseError,
request: request,
};
//////////////////
//This will setup the http request
//Since your using a bearer token and refresh token you will want to add the bearer token the the header of all the requests
function request(config) {
//Set config.headers to existing headers or if none exists set it to an empty object
config.headers = config.headers || {};
//Grab you auth data from storage
//I usually store the object from the /token request in $cookie
var authData = $cookies.getObject("authData");
//If authData exists set it as a Authorization header
if (authData) {
config.headers.Authorization = "Bearer " + authData.access_token;
}
}
function response(response) {
return response || $q.when(response);
}
//Where the 401 magic happens
//If your rejection status is a 401(UnAuthorized)
//You want to request a new token from the authorization service
function responseError(rejection) {
var deferred = $q.defer();
if (rejection.status === 401) {
//You need to manually inject services or factories since your in the .config method
var Authentication = $injector.get("Authentication");
//I usually set up a Authentication Service to do the dirty work so the interceptor doesnt get bloated with code
//See below for reissue token
Authentication.reissueToken()
.then(function () {
//Valid grant
}, function (err) {
//Invalid grant
});
//When this get his the original $http request that failed will get resent to the server
return deferred.promise;
}
return $q.reject(rejection);
}
}
/*Reissue token
* Grabs the authData from storage, using the bearer token make a request to the token endpoint
* If the refresh token hasnt expired the success will send back a new bearer token.
* Update the auth cookie with the new token object
* If the refresh token has expired the request will result in an invalid_grant request will
* be rejected, user must log in again*/
function reissueToken() {
var deferred = $q.defer();
var authData = $cookies.getObject("authData");
if (authData) {
var token = authData.refresh_token;
var data = "grant_type=refresh_token&refresh_token=" + token + "&client_id=" + clientId;
$http.post("/token", data)
.success(function (newToken) {
//Update wherever you store the authorization data
}).error(function (err, status) {
deferred.reject();
});
} else {
deferred.reject();
}
return deferred.promise;
}
你可以阅读更多here ctrl + f for interceptor