为什么需要双token?
token
是为了防止用户信息传来传去导致被劫持,但是假如
token
没有过期时间或者过期很长,那么显然
token
被劫持还是不安全的,
token
就失去了意义。如果token时间短的话,安全性相对提高,但是需要频繁登录,频繁需要服务器返回,对服务器性能是一种浪费,为了解决安全性问题和用户频繁登录问题,采用双
token来
设计。
双token的介绍和优点
介绍
双token机制是为了提高系统安全性而采用的一种措施。它指的是在登录成功后,会生成两个token返回给客户端:
- Access Token:用于访问受限资源,有一定的生命周期,过期需要重新获取。
- Refresh Token:用于刷新Access Token,生命周期较长
优点
- 短期Access Token提高安全性,减小被盗用的时间窗口
- 长期Refresh Token方便免登陆续期,优化用户体验
- 两级验证机制,Access Token遭破解不会立即导致全部资源被盗用
具体流程
- 客户端使用用户名密码请求登录
- 服务端验证成功后,生成Access Token和Refresh Token返回给客户端
- 客户端在Access Token过期前使用它访问受限资源
- Access Token过期后,客户端使用Refresh Token请求新的Access Token
- 服务端验证Refresh Token成功后,生成新的Access Token返回
- 客户端使用新的Access Token继续访问资源
- Refresh Token过期时,需要客户端重新登录获取新的Access Token和Refresh Token
实现步骤
- 生成Access Token和Refresh Token,存储Refresh Token
- 设置不同的过期时间,如Access Token 30分钟,Refresh Token 7天
- 在Access Token过期时验证Refresh Token是否过期以及合法性
- 如果通过验证,根据Refresh Token生成新的Access Token返回
- 如果Refresh Token也过期,返回错误码提示重新登录
代码:
const jwt = require('jsonwebtoken');
const secretKey = 'secret'; // access token密钥
const refreshSecret = 'refreshSecret'; // refresh token密钥
function getAccessToken(req, res) {
let { username, password } = req.body; // 获取登录表单数据
if (username && password) { // 校验用户名和密码
let accessToken = jwt.sign({ username }, secretKey, { expiresIn: '30m' });
// 生成30分钟过期access token
let refreshToken = jwt.sign({ username }, refreshSecret);
// 生成无过期refresh token
res.json({ // 返回access token和refresh token
status: 'ok',
accessToken,
refreshToken
})
} else {
res.json({
status: 'error',
message: '用户名或密码不能为空!' // 登录表单校验失败,返回错误信息
})
}
}
function refreshToken(req, res) { // refresh接口
let { refreshToken } = req.body; // 获取refresh token
if (refreshToken) { // 校验refresh token
let decoded = jwt.verify(refreshToken, refreshSecret);
// 验证refresh token
let accessToken = jwt.sign({ username: decoded.username }, secretKey, { expiresIn: '30m' });
// 生成新的30分钟access token
res.json({
status: 'ok',
accessToken // 返回新的access token
})
} else {
res.json({
status: 'error',
message: '刷新令牌不能为空!' // refresh token校验失败,返回错误信息
})
}
}
app.post('/login', getAccessToken); // 登录接口,获取token
app.post('/refresh', refreshToken); // 刷新接口,刷新access token
版权归原作者 .小汤 所有, 如有侵权,请联系我们删除。