2014-10-27 1 views
6

Я хочу реализовать концепцию «Раздвижного срока действия» с помощью токенов json, используя угловые узлы и узлы jde. Я немного запутался в том, как это сделать, и изо всех сил пытаюсь найти какой-то пример токенов обновления или других материалов, связанных с сеансами с этими технологиями/структурами.Реализация токенов обновления с угловыми и express-jwt

Несколько вариантов я думал, были

  • Создания нового маркеров с каждым запросом после входа
  • Отслеживания выданных маркеров на стороне сервера по

Но я 'честно не уверен, пожалуйста, помогите

+0

У меня в основном один и тот же вопрос, и отправил свой первый проход подход по адресу: https://stackoverflow.com/questions/27408762/jsonwebtoken-activity-based-expiration-vs-issuing-time-based- expiration – rgwozdz

+0

вы можете использовать https://gist.github.com/Mirodil/952e5932c284a2d205db – Mirodil

ответ

12

Мне удалось реализовать этот сценарий.

Что я сделал ...

На сервере:

-Enable АНИ конечная точка для входа в аккаунт. Эта конечная точка ответит Json Web Token в заголовке. Клиентская сторона должна поймать его (с помощью перехватчиков $ http) и сохранить его (я использую локальное хранилище). Клиент также будет управлять обновленными токенами, отправленными сервером.

-При каждом запросе серверу настройте промежуточное ПО в выражении для проверки токена. Сначала я попробовал модуль express-jwt, но jsonwebtoken был для меня правильным.

Для определенных маршрутов вы можете отключить промежуточное программное обеспечение. В этом случае signin и signout.

var jwtCheck = auth.verifyJWT; 
jwtCheck.unless = unless; 
app.use('/api', jwtCheck.unless({path: [ 
    '/api/auth/signin', 
    '/api/auth/signout' 
]})); 

-Попроверочное удостоверение JWT всегда отвечает токеном в заголовке. Если токен необходимо обновить, вызывается обновленная функция.

jwtLib - это моя собственная библиотека, в которой код работает, чтобы создавать, обновлять и извлекать токены jwt.

function(req, res, next) { 
    var newToken, 
     token = jwtLib.fetch(req.headers); 

    if(token) { 
     jwt.verify(token, config.jwt.secret, { 
      secret: config.jwt.secret 
     }, function(err, decoded) { 
      if(err) { 
       return res.status(401).send({ 
        message: 'User token is not valid' 
       }); 
      } 
      //Refresh: If the token needs to be refreshed gets the new refreshed token 
      newToken = jwtLib.refreshToken(decoded); 
      if(newToken) { 
       // Set the JWT refreshed token in http header 
       res.set('Authorization', 'Bearer ' + newToken); 
       next(); 
      } else { 
       res.set('Authorization', 'Bearer ' + token); 
       next(); 
      } 
     }); 
    } else { 
     return res.status(401).send({ 
      message: 'User token is not present' 
     }); 
    } 
}; 

-Функция обновления (jwtLib). Поскольку для аргумента требуется декодированный токен, см. Выше, что jsonwebtoken разрешает декодирование при вызове jwt.verify().

Если вы создаете во время подписания токена с истечением 4 часов и истекаете в течение 1 часа (1 * 60 * 60 = 3600 секунд), это означает, что токен будет обновлен, если пользователь неактивен для 3 часа и более, но не более 4 часов, потому что в этом случае процесс проверки завершится неудачно (1 час освежения). Это позволяет избежать генерации нового токена для каждого запроса, только если токен истечет в это время.

module.exports.refreshToken = function(decoded) { 
    var token_exp, 
     now, 
     newToken; 

    token_exp = decoded.exp; 
    now = moment().unix().valueOf(); 

    if((token_exp - now) < config.jwt.TOKEN_REFRESH_EXPIRATION) { 
     newToken = this.createToken(decoded.user); 
     if(newToken) { 
      return newToken; 
     } 
    } else { 
     return null; 
    } 
}; 

На клиенте (Angularjs):

-enable стороне клиента для входа в систему. Это вызывает конечную точку сервера. Я использую Http Basic Authentication, закодированную с base64. Вы можете использовать угловой модуль base64 для кодирования электронной почты: пароль Обратите внимание, что при успешном выполнении я не храню токен на localStorage или Cookie. Это будет управляться http Interceptor.

//Base64 encode Basic Authorization (email:password) 
$http.defaults.headers.common.Authorization = 'Basic ' + base64.encode(credentials.email + ':' + credentials.password); 
return $http.post('/api/auth/signin', {skipAuthorization: true}); 

-configure HTTP-перехватчиков отправить маркер на сервер при каждом запросе и хранить маркер на ответ. Если получен обновленный токен, он должен быть сохранен.

// Config HTTP Interceptors 
angular.module('auth').config(['$httpProvider', 
    function($httpProvider) { 
     // Set the httpProvider interceptor 
     $httpProvider.interceptors.push(['$q', '$location', 'localStorageService', 'jwtHelper', '$injector', 
      function($q, $location, localStorageService, jwtHelper, $injector) { 
       return { 
        request: function(config) { 
         var token = localStorageService.get('authToken'); 
         config.headers = config.headers || {}; 

         if (token && !jwtHelper.isTokenExpired(token)) { 
          config.headers.Authorization = 'Bearer ' + token; 
         } 
         return config; 
        }, 
        requestError: function(rejection) { 
         return $q.reject(rejection); 
        }, 
        response: function(response) { 
         //JWT Token: If the token is a valid JWT token, new or refreshed, save it in the localStorage 
         var Authentication = $injector.get('Authentication'), 
          storagedToken = localStorageService.get('authToken'), 
          receivedToken = response.headers('Authorization'); 
         if(receivedToken) { 
          receivedToken = Authentication.fetchJwt(receivedToken); 
         } 
         if(receivedToken && !jwtHelper.isTokenExpired(receivedToken) && (storagedToken !== receivedToken)) { 

          //Save Auth token to local storage 
          localStorageService.set('authToken', receivedToken); 
         } 
         return response; 
        }, 
        responseError: function(rejection) { 
         var Authentication = $injector.get('Authentication'); 
         switch (rejection.status) { 
          case 401: 
           // Deauthenticate the global user 
           Authentication.signout(); 
           break; 
          case 403: 
           // Add unauthorized behaviour 
           break; 
         } 

         return $q.reject(rejection); 
        } 
       }; 
      } 
     ]); 
    } 
]); 
+0

В этом решении кажется, что вы просто выпускаете новый JWT, если старый истек. Это разрушает всю безопасность JWT, которая не может быть использована после истечения срока действия, даже не обновлять и выдавать новый токен. Сервер действительно должен был выпустить еще один токен, называемый токеном обновления, который он сохранит в базе данных и отправит его клиенту. Током обновления будет тот, который используется для получения нового токена доступа JWT, как только предыдущий срок истек. – stephen

+0

refreshToken() вызывается только в том случае, если пользователь аутентифицирован, поэтому нет проблемы с безопасностью. refreshToken() генерирует новый токен, если истечение времени находится в временном окне TOKEN_REFRESH_EXPIRATION, в противном случае возвращает значение null. В любом случае этот фрагмент кода был написан некоторое время назад. Это все еще актуально, но, возможно, какой-то другой подход может быть лучше. – almoraleslopez

+0

@almoraleslopez, когда кто-то украл маркер ur, хакер будет аутентифицирован и может обновить без ограничений – AgBorkowski

Смежные вопросы