2014-10-27 64 views
6

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

我在想有几个选项分别为

  • 沿

但我生成与每个请求新的令牌在首次登录后在服务器端发出的令牌的

  • 比方追查老实说不知道,请帮忙

  • +0

    我有基本相同的问题,并张贴了我的第一个回合方法在:https://stackoverflow.com/questions/27408762/jsonwebtoken-activity-based-expiration-vs-issuing-time-based-到期 – rgwozdz 2014-12-10 19:05:34

    +0

    您可以使用https://gist.github.com/Mirodil/952e5932c284a2d205db – Mirodil 2015-08-17 12:45:56

    回答

    12

    我设法实现这种情况。

    我做了什么......

    在服务器上:

    -Enable进行登录的API端点。该端点将使用标题中的Json Web令牌进行响应。客户端必须捕获它(使用$ http拦截器)并保存它(我使用本地存储)。客户端还将管理由服务器发送的刷新令牌。

    - 在每次向服务器发送请求时,都会配置express中间件来验证令牌。起初,我尝试了express-jwt模块,但jsonwebtoken对我来说是正确的。

    对于特定的路线,您可能希望禁用中间件。在这种情况下,登录和注销。

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

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

    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)。由于参数需要解码的标记,请参阅上面的说明,当调用jwt.verify()时,jsonwebtoken解析已解码的标记。

    如果您在签入过程中创建了一个过期时间为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用于登录的客户端。这将调用服务器端点。我使用base64编码的Http Basic Authentication。 您可以使用base64角模块来编码电子邮件:密码 请注意,成功后,我不会将令牌存储在localStorage或Cookie上。这将由http拦截器管理。

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

    - 配置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一旦过期而无法使用的整个安全性,甚至不能刷新和发布新的令牌。服务器确实应该发布另一个称为刷新令牌的令牌,它将保存到数据库中并将其发送给客户端。刷新标记将用于在前一个标记过期后获取新的JWT访问标记。 – stephen 2017-05-24 05:24:02

    +0

    refreshToken()仅在用户通过身份验证时才会调用,因此不存在安全问题。如果到期时间在TOKEN_REFRESH_EXPIRATION的时间窗口内,则refreshToken()会生成一个新标记,否则返回null。无论如何,这段代码是前一段时间写的。这仍然有效,但也许其他一些方法可能会更好。 – almoraleslopez 2017-05-29 08:27:27

    +0

    @almoraleslopez当有人盗取你的令牌时,黑客将被验证并刷新无限制 – AgBorkowski 2017-11-03 10:40:58