AngularJS перенаправляет на вход в систему, если токен обновления (JWT) становится неавторизованным (ответ 401) - PullRequest
0 голосов
/ 18 февраля 2019

Возникает проблема с перенаправлением пользователя на страницу входа, если токен обновления (jwt) становится неавторизованным (после истечения срока действия первого токена).Существует 2 сценария отмены авторизации токенов:

  • 1-й: Когда срок действия токена jwt истекает на основании ответа 401, вызывается новая служба обновления для генерации нового токена через $ http-перехватчики (config).

  • 2-й: когда токен обновления также получает неавторизованный (401) ответ, это когда пользователь должен перенаправить на страницу входа.

Я могу отправить токен обновления по первому сценарию и он работает нормально, как и ожидалось, но я не могу перенаправить пользователя на страницу входа, если токен обновления также получает неавторизованный (401) ответ.

Вот мой код:

authInterceptor.service.js

angular.module('someApp').factory('AuthorizationTokenService', AuthorizationTokenService);

AuthorizationTokenService.$inject = ['$q', '$injector', '$cookies'];
function AuthorizationTokenService($q, $injector, $cookies) {
  // Local storage for token
  var tokenVM = {
    accessToken: null
  };

  // Subscribed listeners which will get notified when new Access Token is available
  var subscribers = [];

  // Promise for getting new Access Token from backend
  var deferedRefreshAccessToken = null;

  var service = {
    getLocalAccessToken: getLocalAccessToken,
    refreshAccessToken: refreshAccessToken,
    isAccessTokenExpired: isAccessTokenExpired,
    subscribe: subscribe
  };

  return service;

  ////////////////////////////////////

  // Get the new Access Token from backend
  function refreshAccessToken() {

    // If already waiting for the Promise, return it.
    if( deferedRefreshAccessToken ) {

      return deferedRefreshAccessToken.promise 

    } else {

      deferedRefreshAccessToken = $q.defer();

      // Get $http service with $injector to avoid circular dependency
      var http = $injector.get('$http');

      http({
        method: 'POST',
        url: 'api_url',
        params: {
          grant_type: 'refresh',
          id_token: $cookies.get('access_token')
        }
      })
        .then(function mySucces(response) {
          var data = response.data;
          if( data ){
            // Save new Access Token
            $cookies.put('access_token', data.access_token);

            if( $cookies.get('access_token') ) {

              // Resolve Promise
              deferedRefreshAccessToken.resolve(data.access_token);

              // Notify all subscribers
              notifySubscribersNewAccessToken(data.access_token);
              deferedRefreshAccessToken = null;
            }
          }
        }, function myError(error) {
          deferedRefreshAccessToken.reject(error);
          deferedRefreshAccessToken = null;
        });

      return deferedRefreshAccessToken.promise;
    } 

  }

  function getLocalAccessToken() {
    // get accesstoken from storage - $cookies
    if ( $cookies.get('access_token') ) {
      var access_token = $cookies.get('access_token')
      return access_token;
    }
  }

  function isAccessTokenExpired() {
    // Check if expiresAt is older then current Date
  }

  function saveToken(accessToken) {
    // get accesstoken from storage - $cookies
    var access_token = $cookies.put('access_token');

    console.log('access_token ' + access_token);

    return access_token;
  }

  // This function will call all listeners (callbacks) and notify them that new access token is available
  // This is used to notify the web socket that new access token is available
  function notifySubscribersNewAccessToken(accessToken) {
    angular.forEach(subscribers, function(subscriber) {
      subscriber(accessToken);
    });
  }

  // Subscribe to this service. Be notifyed when access token is renewed
  function subscribe(callback) {
    subscribers.push(callback);
  }
}

И в Config (app.js)

config.$inject = ['$stateProvider', '$urlRouterProvider', '$httpProvider'];
function config($stateProvider, $urlRouterProvider, $httpProvider) {

  // Push httpRequestInterceptor
  // $httpProvider.interceptors.push('httpRequestInterceptor');

  //Intercept all http requests
  $httpProvider.interceptors.push(['$injector', '$q', "AuthorizationTokenService", "$cookies", function ($injector, $q, AuthorizationTokenService, $cookies) {
    var cachedRequest = null;

    return {
      request: function (config) {
        //If request if for API attach Authorization header with Access Token
        if (config.url.indexOf("api") != -1) {
          // var accessToken = AuthorizationTokenService.getLocalAccessToken();
          console.log('cookie ' + $cookies.get('access_token'));
          config.headers.Authorization = 'Bearer ' + $cookies.get('access_token');
        }
        return config;
      },
      responseError: function (response) {
        switch (response.status) {
          // Detect if reponse error is 401 (Unauthorized)
          case 401:

          // Cache this request
          var deferred = $q.defer();
          if(!cachedRequest) {
            // Cache request for renewing Access Token and wait for Promise
            cachedRequest = AuthorizationTokenService.refreshAccessToken();
          }

          // When Promise is resolved, new Access Token is returend 
          cachedRequest.then(function(accessToken) {
            cachedRequest = null;
            if (accessToken) {
              // Resend this request when Access Token is renewed
              $injector.get("$http")(response.config).then(function(resp) {
                // Resolve this request (successfully this time)
                deferred.resolve(resp);
              },function(resp) {
                deferred.reject();
                console.log('success: refresh token has expired');
              });
            } else {
              // If any error occurs reject the Promise
              console.log('error: refresh token has expired');
              deferred.reject();
            }
          }, function(response) {
            // If any error occurs reject the Promise
            cachedRequest = null;
            deferred.reject();
            return;
          });

          return deferred.promise;
        }

        // If any error occurs reject the Promise
        return $q.reject(response);
      }
    };
  }]);
}

Оба в сервисе & config , я пытался реализовать это перенаправление пользователей на основе двойного 401 (средний токен обновления также истекает и отвечает 401).

Я также пытался с условием множественного потомка 401, но это не сработало.(пример ниже)

responseError: function (response) {
  // Detect if reponse error is 401 (Unauthorized)
  if (response.status === 401) {

    // Cache this request
    var deferred = $q.defer();
    if(!cachedRequest) {
      // Cache request for renewing Access Token and wait for Promise
      cachedRequest = AuthorizationTokenService.refreshAccessToken();
    }

    // When Promise is resolved, new Access Token is returend 
    cachedRequest.then(function(accessToken) {
      cachedRequest = null;
      if (response.status === 401) {
        console.log('refresh token also expired');
        $location.path('/login');
      } else {
        // Resend this request when Access Token is renewed
        $injector.get("$http")(response.config).then(function(resp) {
          // Resolve this request (successfully this time)
          deferred.resolve(resp);
        },function(resp) {
          deferred.reject();
          console.log('success: refresh token has expired');
        });
      }
    }, function(response) {
      // If any error occurs reject the Promise
      cachedRequest = null;
      deferred.reject();
      return;
    });

    return deferred.promise;
  }
}

Основываясь на приведенном выше коде, пожалуйста, сообщите мне, что я делаю неправильно, или, возможно, что-то не так с логином / реализацией.В любом случае, пожалуйста, помогите мне.Спасибо

1 Ответ

0 голосов
/ 07 марта 2019

Мне удалось решить эту проблему с помощью следующих строк кода:

Config (app.js)

// Cache this request
var deferred = $q.defer();
if(!cachedRequest) {
    // Cache request for renewing Access Token and wait for Promise
    cachedRequest = AuthorizationTokenService.refreshAccessToken();
} else {
    // this is where it checks for request token expiry
    do_logout();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...