【问题标题】:Storing Refresh Token In JavaScript, Getting New Access Token在 JavaScript 中存储刷新令牌,获取新的访问令牌
【发布时间】:2015-09-17 00:11:33
【问题描述】:

我有一个 ASP.NET Web API,它在登录时返回一个 OAuth2 不记名令牌。我计划通过 JavaScript 将刷新令牌存储在 cookie 中。我应该在我的 JS 中的哪个位置检查访问令牌是否已过期以获取新的...在每个需要身份验证的后续 API 调用之前或在某种计时器循环上?这将是一个异步 Web 应用程序,所以我认为计时器循环并不理想。有什么想法吗?

【问题讨论】:

    标签: oauth-2.0


    【解决方案1】:

    我不会那样做,如果您可以在 javascript 中访问您的 cookie,这意味着任何 XSS 脚本都可以劫持它。本地存储也不是一个安全的地方。

    我建议在服务器上生成令牌后立即将令牌存储在安全的 http-only cookie 中,并将该 cookie 附加到响应中。

    如果您将 WebAPI 2 与 oAuth 一起使用,则在您的授权服务器提供程序中,您可以覆盖 TokenEndPointReponse

        /// <summary>
        /// Called when a request to the Token endpoint is finished and gonna be sent back to the client
        /// We intercept the token and force the client to write a cookie containing the token value.
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public override System.Threading.Tasks.Task TokenEndpointResponse(OAuthTokenEndpointResponseContext context)
        {
    
            // We set our auth cookie configuration
            var cookieOptions = new CookieOptions
            {
                HttpOnly = true, // immune to JS manipulation
                Secure = insertMagicLogicHere(), // we set the cookie to secure in production environment
                Path = "/",
                Domain = ".mycooldomain.com",
                Expires = DateTime.Now.AddMinutes(GlobalAuthSettings.AuthServerOptions.AccessTokenExpireTimeSpan.TotalMinutes)
            };
    
            var refreshTokenId = context.OwinContext.Get<string>("as:refreshTokenId");
    
            // We build the authentication object to store in our cookie
            var ourTokenObject = new AuthCookie
            {
                username = context.Properties.Dictionary["userName"],
                token = context.AccessToken,
                useRefreshTokens = true,
                refreshtoken = refreshTokenId
            };
    
            // We send it back 
            context.Response.Cookies.Append("mySecureCookie", JsonConvert.SerializeObject(ourTokenObject), cookieOptions);
    
            return base.TokenEndpointResponse(context);
        }
    

    然后在 javascript 中,您需要确保 cookie 随每个请求一起发送。 您可以设置一些 Owin 中间件来拦截请求,从 cookie 中解析令牌并将令牌设置为授权标头。

    要刷新令牌,您可以配置一个 Http 拦截器,如果您收到 401 将自动刷新令牌,如果刷新令牌成功则重试请求。

    这是 Angular 中的一些代码

        //#region Private members
    
        var _retryHttpRequest = function (config, deferred) {
            $rootScope.httpRetries++;
            console.log('autorefresh');
            $http = $http || $injector.get('$http') || $injector.post('$http');
            $http(config).then(
            function (success) {
                $rootScope.httpRetries--;
                deferred.resolve(success);
            },
            function (error) {
                console.log("Error in response", rejection);
                deferred.reject(error);
            });
        };
    
        var _refreshToken = function () {
            var deferred = $q.defer();
            // refresh_token=refreshToken because the refresh_token is serialized in the http cookie and not accessible in javascript, the refreshToken is however stored in the cookie so we can resolve that server side
            var data = "grant_type=refresh_token&refresh_token=refreshToken&client_id=" + appState.clientId;
            $http = $http || $injector.get('$http');
            $http.post(authUrl + '/token', data, {
                headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
            }).success(function (response) {
                deferred.resolve(response);
            }).error(function (err, status) {
                deferred.reject(err);
            });
            return deferred.promise;
        };
    
        //#endregion Private members
    
        //#region Public members
    
        function _request(config) {
            config.withCredentials = true; // forces angular to send cookies in each request
            return config;
        }
    
        // intercept response errors and refresh token if need be
        function _responseError(rejection) {
            var deferred = $q.defer();
            if (rejection.status === 401 || rejection.status === 403) {
                if ($rootScope.httpRetries < 2) {
                    console.log("calling refreshToken()");
                    _refreshToken().then(function (response) {
                        console.log("token refreshed, retrying to connect");
                        // retry the request if the token was successfully refreshed
                        _retryHttpRequest(rejection.config, deferred);
                    }, function (error) {
                        console.log("_refreshToken error", error);
                        deferred.reject(rejection);
                        window.location.reload(true);
                    });
                }
                else {
                    console.log("_refreshToken error", error);
                    deferred.reject(rejection);
                    window.location.reload(true);
                }
    
            } else {
                console.log("Error in response", rejection);
                deferred.reject(rejection);
            }
            return deferred.promise;
        };
        //#endregion Public members
    

    希望这会有所帮助。

    【讨论】:

      猜你喜欢
      • 2021-07-16
      • 2021-09-13
      • 2021-10-07
      • 1970-01-01
      • 2013-03-24
      • 1970-01-01
      • 2015-07-19
      • 2017-03-22
      • 2021-07-08
      相关资源
      最近更新 更多