jwt token的payload主要内容
"token": {
"trigger": "signIn",
"iat": 1716279911,
"exp": 1724055911,
"jti": "f8f683ce-08a2-44b1-b109-139fb297959d"
}
其中iat 是当前令牌分发时间,每次登录重新生成令牌,刷新该值.所以具体思路是,重置密码的时候记录下当前重置时间
const user = await prisma.user.update({
where: {
email: input.email,
},
data: {
password: getSHA256ofJSON(input.newPassword),
},
})
await prisma.userResetToken.update({
where: { identifier: input.email },
data: { resetTime: new Date() },
})
然后在next-auth jwt回调中进行判断
if (token.email && token.exp && token.iat) {
const userResetToken = await prisma.userResetToken.findFirst({
where: { identifier: token.email },
})
if (userResetToken && userResetToken.resetTime) {
const resetTime = userResetToken.resetTime
console.log('重置token exp')
// token.exp = '1716107284' //想设置下token的exp 为一个过期时间,但是并没有更新到客户端
// 如果jwt 创建时间少于重置密码最新时间,说明jwt过期了
if (
resetTime && (token.iat as number) < resetTime.getTime()
) {
console.log('jwt过期 重新登录')
return null
}
}
}
原本想设置token 过期并可以更新到客户端.重写jwt 的decode
async decode(params: JWTDecodeParams) {
const result = (await decode({
token: params.token,
secret: params.secret ??process.env.NEXTAUTH_SECRET ,
})) as any
return result
},
重写jwt 的encode
async encode(params: JWTEncodeParams) {
const { token, secret } = params
// 创建时间小于当前账户的重置密码时间,让token 过期
if (token && token.email && token.exp) {
const userResetToken = await prisma.userResetToken.findFirst({
where: { identifier: token.email },
})
if (userResetToken) {
const resetTime = userResetToken.resetTime
// 如果jwt 创建时间少于重置密码最新时间,说明jwt过期了
if (resetTime && (token.iat as any) < resetTime.getTime() ) {
// token.email = "test@123.com"
token.exp = Date.now()
}
}
}
const encodedToken = encode(params,secret)
return encodedToken
},
测试流程。
浏览器A登录 浏览器B登录,浏览器A重置密码,查看浏览器B请求,登录状态已经无效
其他方案:
1 .黑名单校验
记录用户登录的每一个token
修改密码后让之前的token 全部列入黑名单
每次用户请求服务器都校验token是否在黑名单
问题:(还不清楚在next-auth 中怎么实现,我们现在没有手动记录token)
- 版本号校验
记录用户登录的每一个token,设置一个版本号
修改密码同时修改用户token版本号(加1==)
访问时从token中取出版本号和用户id 进行对比,不一致就不通过
问题:(还不清楚在next-auth 中怎么实现,我们现在没有手动记录token)
无为而治
只让前端清理token,后端不理会。(大多数)