使用angular和express-jwt实现刷新令牌

我想使用angular,nodejs和express-jwt来实现带有json web令牌的Sliding过期概念。 我对如何做到这一点感到有些困惑,并且正在努力寻找更新令牌或与这些技术/框架相关的其他材料的任何示例。

我正在考虑的几个选项是

  • 在初始login后,为每个请求生成一个新的令牌
  • 跟踪服务器端发出的令牌

但是我真的不确定,请帮忙

我设法实现这种情况。

我做了什么…

在服务器上:

– 为login启用API端点。 此端点将使用标题中的Json Web令牌进行响应。 客户端必须捕获它(使用$ http拦截器)并保存(我使用本地存储)。 客户端也将pipe理由服务器发送的刷新的令牌。

– 对服务器的每一个请求都要configuration一个express的中间件来validation令牌。 起初我尝试了express-jwt模块,但是jsonwebtoken对我来说是正确的。

对于特定的路线,您可能需要禁用中间件。 在这种情况下,login和注销。

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

– 中间件verifyJWT总是在头部响应一个令牌。 如果需要刷新令牌,则会调用刷新的函数。

jwtLib是我自己的库,代码用于创build,刷新和获取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' }); } }; 

– 刷新function(jwtLib)。 作为参数需要一个解码的标记,请参阅上面的jsonwebtokenparsing调用jwt.verify()时解码。

如果您在login期间创build了一个过期4小时的令牌,并且刷新到期时间为1小时(1 * 60 * 60 = 3600秒),这意味着如果用户已经停用了3个小时或更长时间,令牌将会刷新但不超过4小时,因为在这种情况下validation过程将失败(刷新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)上:

– 启用客户端login。 这将调用服务器端点。 我使用base64编码的Http Basic Authentication。 您可以使用base64angular模块来编码电子邮件:密码请注意,成功之后,我不会将该令牌存储在localStorage或Cookie上。 这将由http拦截器pipe理。

 //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}); 

– configurationhttp拦截器在每个请求中将令牌发送到服务器,并将令牌存储在响应中。 如果收到刷新的令牌,则必须存储该令牌。

 // 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); } }; } ]); } ]);