利用Redis撤销JSON Web Token产生的令牌

来源:互联网 发布:淘宝宝贝描述 编辑:程序博客网 时间:2024/06/07 23:50

利用Redis撤销JSON Web Token产生的令牌

作者:chszs,版权所有,未经同意,不得转载。博主主页:http://blog.csdn.net/chszs

早先的博文讨论了在Angular.js和Node.js中使用jsonwebtoken实现认证授权的案例。这里要说明一下,当用户点击了“注销”按钮,用户的令牌在Angular端会从授权认证服务AuthenticationService中移除,但是此令牌仍旧是有效的,还可以被攻击者窃取到,用于API调用,直至jsonwebtoken的有效时间结束。

为了避免此情况的发生,可以使用Redis数据库来存储已撤销的令牌——当用户点击注销按钮时。且令牌在Redis存储的时间与令牌在jsonwebtoken中定义的有效时间相同。当有效时间到了后,令牌会自动被Redis删除。最后,创建Node.js应用来检查各终端上传的令牌在Redis中是否存在。

一、在Node.js中配置Redis

首先,必须在Node.js中安装Redis客户端连接库,并配置客户端能够连接到Redis实例。如下:

var redis = require('redis');var redisClient = redis.createClient(6379);redisClient.on('error', function (err) {    console.log('Error ' + err);});redisClient.on('connect', function () {    console.log('Redis is ready');});exports.redis = redis;exports.redisClient = redisClient;

二、令牌管理器&中间件

要保存已移除的令牌,需要创建一个函数来获取Header的参数,并取出令牌,把它作为键名存储到Redis,至于键值就无所谓了。

var redisClient = require('./redis_database').redisClient;var TOKEN_EXPIRATION = 60;var TOKEN_EXPIRATION_SEC = TOKEN_EXPIRATION * 60;exports.expireToken = function(headers) {    var token = getToken(headers);    if (token != null) {        redisClient.set(token, { is_expired: true });        redisClient.expire(token, TOKEN_EXPIRATION_SEC);    }};var getToken = function(headers) {    if (headers && headers.authorization) {        var authorization = headers.authorization;        var part = authorization.split(' ');        if (part.length == 2) {            var token = part[1];            return part[1];        }        else {            return null;        }    }    else {        return null;    }};

接下来,可以创建一个中间件来验证用户提供的令牌是否有效:

// Middleware for token verificationexports.verifyToken = function (req, res, next) {    var token = getToken(req.headers);    redisClient.get(token, function (err, reply) {        if (err) {            console.log(err);            return res.send(500);        }        if (reply) {            res.send(401);        }        else {            next();        }    });};

方法verifyToken是一个中间件,它从请求的Header部分取出令牌,并在Redis中进行查询。如果令牌发现了,则响应HTTP 401。否则,继续处理,让用户访问受限制的API。

当用户点击注销按钮时,平台端必须调用expireToken方法。

exports.logout = function(req, res) {    if (req.user) {        tokenManager.expireToken(req.headers);        delete req.user;        return res.send(200);    }    else {        return res.send(401);    }}

最后,让之前开发的中间件模块生效:

//Loginapp.post('/user/signin', routes.users.signin);//Logoutapp.get('/user/logout', jwt({secret: secret.secretToken}), routes.users.logout);//Get all postsapp.get('/post/all', jwt({secret: secret.secretToken}), tokenManager.verifyToken, routes.posts.listAll);//Create a new postapp.post('/post', jwt({secret: secret.secretToken}), tokenManager.verifyToken , routes.posts.create);//Edit the post idapp.put('/post', jwt({secret: secret.secretToken}), tokenManager.verifyToken, routes.posts.update);//Delete the post idapp.delete('/post/:id', jwt({secret: secret.secretToken}), tokenManager.verifyToken, routes.posts.delete);

现在,每次用户要请求受限的服务时,我们都需要解密其令牌,并检查令牌是否被撤销。

0 0
原创粉丝点击