Angular Refresh令牌授权问题

Angular Refresh Token Authorization Issue

本文关键字:问题 授权 令牌 Refresh Angular      更新时间:2023-09-26

我有一个Angular客户端。我使用Asp.NetWebApi创建了一个承载令牌授权系统。它使用具有短暂指定时间的访问令牌,并使用具有长期指定时间的刷新令牌。当访问令牌过期,并且向具有多个$http请求的页面发出请求时,我遇到了一个问题。我设置了一个用于检索数据的服务,如果第一个响应返回401,它就会从刷新令牌服务器获取新令牌,然后对数据进行第二次请求。现在发生的情况是,两个安全请求几乎同时启动,它们都失败401,它们都得到了一个新的令牌,第一个令牌检索被第二个令牌检索无效。

我突然想到了两个解决方案。1.)将呼叫链接到我的数据服务。2) 按照页面对所有数据进行一次请求的方式排列我的请求。我不打算详细说明为什么这两种方法是不可接受的,我相信你知道为什么。

我考虑过在其他请求正在进行时将请求"锁定"到令牌服务器,或者为令牌请求设置队列服务,很明显,我正在努力避免瓶颈,同时保持我的承诺链的完整性。

我相信其他人也经历过这种情况,只是想知道其他人采取了什么措施。

提前感谢!

是否覆盖angular app.config方法中的$httpProvider?

使用$httpProvider.interceptors.push(<Your auth interceptor>);

如果没有,拦截器将监控你的angular应用程序发出的所有请求,并使用下面的"可选功能"进行处理。

你可以建立一个工厂来处理所有的事情,比如下面的裸骨头。这基本上一次只接受一个请求。因此,对于模拟请求问题,第一个请求将通过工厂请求函数并设置头。然后将发出请求,并点击响应功能。如果响应返回错误,则将调用工厂响应错误函数,如果将评估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;
    }

您可以在这里阅读更多关于拦截器的ctrl+f