简述JWT系统实现
两种登陆状态
有状态登陆
为了保证客户端cookie的安全性,服务端需要记录每次会话的客户端信息,从而识别客户端身份,根据用户身份进行请求的处理,典型的设计如tomcat中的session。
例如登录:用户登录后,我们把登录者的信息保存在服务端session中,并且给用户一个cookie值,记录对应的session。然后下次请求,用户携带cookie值来,我们就能识别到对应session,从而找到用户的信息。
缺点是什么:
- 服务端保存大量数据,增加服务端压力
- 服务端保存用户状态,无法进行水平扩展
- 客户端请求依赖服务端,多次请求必须访问同一台服务器
无状态登陆
微服务及集群的每个服务队外都是提供REST风格的接口,而这些接口有一个重要的规范就是服务的无状态。
- 也就是服务端不保存任何客户端的信息
- 客户端的每次请求都必须自备描述信息,通过这些信息识别客户端身份
我们不禁想问,带来的收益是什么
- 任何多次请求不需要访问同一台服务器
- 服务器的集群和状态对客户端透明
- 服务端可以任意的前一和伸缩
- 减小服务端的存储压力
无状态登陆流程
- 当客户端第一次请求服务时候,服务端对于用户进行信息认证
1
2
3
4
5boolean isValidToken = validateToken(token);
if (!isValidToken) {
handleInvalidToken(request);
return null;
} - 认证通过后,将用户信息进行加密形成token,返回给客户端,作为登陆凭证
1
2
3
4
5
6
7
8
public String login(String username, String password) {
if (!userDao.existsByUserNameAndPassword(username, password)) {
logger.info("登录失败:用户名或密码错误");
return null;
}
return generateNewJwt(username);
} - 以后每次请求,客户端都携带认证的token
1
2
3
4
5
6fetch('https://example.com/api/endpoint', {
method: 'GET',
headers: {
'Authorization': `Bearer ${storedToken}`, // 将 Token 添加到 Authorization Header
},
}); - 服务对于token进行解密,判断是否有效
什么是JWT
JWT,全称是Json Web Token, 是JSON风格轻量级的授权和身份认证规范,可实现无状态、分布式的Web应用授权;
整个过程的关键点是token是识别客户端身份的唯一标识,如果加密不够严密,那么将会出现问题
我们将使用JWT + RSA非对称加密
在简单的复习一下RSA的加密过程
我们需要知道(N,e)公钥和(N,d)私钥,将私钥进行保存
将想要加密的消息进行{\displaystyle c=n^{e}{\bmod {N}}}
我们需要进行传递c
然后我们就可以使用快速幂等的方法去获得想要的信息n
{\displaystyle n=c^{d}{\bmod {N}}}
JWT包含三部分数据
header: 包含token类型:jwt,加密方式:base64
payload: 用户身份信息以及token的签发时间,过期时间和签发人等
signature:整个数据的认证信息,再加上secret
同时jwt也有一些缺陷,例如
无法动态更新用户信息,也就是无法主动失效的问题
痛点:JWT一旦签发,其中的信息(如角色、权限)在有效期内是固定的。如果用户权限在令牌有效期内发生变化(如被管理员修改),旧令牌仍然有效,直到过期。
影响:可能导致权限不一致的问题。
解决思路:
缩短令牌有效期,强制用户定期刷新。
结合服务端检查,每次请求时验证用户当前权限(但这会增加服务器负担,部分违背无状态初衷)。
使用黑名单机制,权限变更时将旧令牌加入黑名单(你已经实现了类似的方案)。