2015-09-17 3 views
1

У меня есть веб-API ASP.NET, который возвращает маркер-носитель OAuth2 при входе в систему. Я планирую хранить токен обновления в cookie через JavaScript. Где в моем JS я должен проверить, истек ли токен доступа для получения нового ... прямо перед каждым последующим вызовом API, требующим проверки подлинности или на каком-то таймерном цикле? Это будет асинхронное веб-приложение, поэтому я не думал, что цикл таймера будет идеальным. Есть идеи?Хранение значка обновления в JavaScript, получение нового токена доступа

ответ

0

Я бы этого не сделал, если вы можете получить доступ к своему файлу cookie в javascript, это означает, что любой скрипт XSS может его захватить. Localstorage также не является безопасным местом.

Я бы порекомендовал хранить токен в защищенном http-only cookie сразу после того, как токен был сгенерирован на сервере, и добавьте этот файл cookie в ответ.

Если вы используете WebAPI 2 с OAuth, в поставщика authorizationServer вы можете переопределить 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 вы должны убедиться, что печенье отправляется с каждым запросом. Вы можете настроить промежуточное программное обеспечение Owin для перехвата запросов, проанализировать токен из файла cookie и установить токен в заголовок авторизации.

Чтобы обновить токен, вы можете настроить Http Interceptor, который автоматически обновит токен, если вы получите 401, и повторите запрос, если refreshtoken был успешным.

Вот код в угловом

//#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 

Надеется, что это помогает.