认识JWT令牌
我们需要先学习最常见的JWT令牌,官网:jwt.io
JWT(JSON Web Token)令牌是一种基于JSON的开放标准(RFC 7519),用于在网络应用中传输信息的令牌。
JWT令牌由三部分组成:头部(Header)、载荷(Payload)和签名(Signature)。
- 头部通常包含令牌的类型和使用的算法(例如,HMAC SHA256或RSA)。
- 载荷包含要传输的信息,如用户ID、角色或其他自定义的数据。
- 签名是用于验证令牌的一部分,确保令牌在传输过程中没有被篡改。
JWT的优点包括
- 服务端无需存储会话信息:传统的session方式需要服务端存储用户的会话信息,包括用户的身份认证信息和会话状态。但是使用Token,服务端无需存储任何会话信息,所有的认证信息都包含在Token中,使得服务端变得无状态,大大减轻了服务器的负担,同时也方便了服务的水平扩展。
- 减少网络延迟:传统的session方式需要在每次请求中都携带会话标识,即使是无状态的RESTful API也需要携带身份认证信息。而使用Token,身份认证信息已经包含在Token中,只需要在请求的Authorization头部携带Token即可,减少了每次请求的数据量,减少了网络延迟。
- 客户端无需存储会话信息:传统的session方式,客户端需要存储会话标识,以便在每次请求中携带。而使用Token,客户端只需要保存Token即可,方便了客户端的存储和管理。
- 跨域支持:Token可以在各个不同的域名之间进行传递和使用,因为Token是通过签名来验证和保护数据完整性的,可以防止未经授权的修改。
注意事项
在使用JWT时,JWT的3部分分别进行Base64编码后用.
进行连接形成最终需要传输的字符串。首先将负载部分的信息进行加密生成令牌,然后将该令牌作为Authorization请求头部的值发送给资源服务器。资源服务器可以通过验证令牌的签名来确保令牌的真实性和完整性。如果验证成功,资源服务器就可以使用负载中的信息进行后续操作。
需要注意的是,由于JWT是基于签名验证的,所以令牌中的信息是可以被解密的。因此,敏感信息(如密码)不应该被存储在JWT的负载部分中。
所以JWT令牌通常用于认证和授权,以验证用户的身份并授予对特定资源的访问权限。在前后端分离的应用程序中,JWT令牌被广泛用于身份验证和API访问控制。
快速使用JWT
JWT令牌实际上是一种经过加密的JSON数据,其中包含了用户名字、用户ID等信息,我们可以直接解密JWT令牌得到用户的信息,我们来试试,导入JWT支持库依赖:
<dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>4.3.0</version> </dependency>
要生成一个JWT令牌非常简单:
public static void main(String[] args) { String jwtKey = "abcdefghijklmn"; //使用一个JWT秘钥进行加密 Algorithm algorithm = Algorithm.HMAC256(jwtKey); //创建HMAC256加密算法对象 String jwtToken = JWT.create() .withClaim("id", 1) //向令牌中塞入自定义的数据 .withClaim("name", "jinze") .withClaim("role", "admin") .withExpiresAt(new Date(2024, Calendar.FEBRUARY, 1)) //JWT令牌的失效时间 .withIssuedAt(new Date()) //JWT令牌的签发时间 .sign(algorithm); //使用上面的加密算法进行加密,完成签名 System.out.println(jwtToken); //得到最终的JWT令牌 }
可以看到最后得到的JWT令牌就长这样:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoiYWRtaW4iLCJuYW1lIjoiamluemUiLCJpZCI6MSwiZXhwIjo2MTY2NDg2MDgwMCwiaWF0IjoxNjk0MTY0NTcwfQ.yvmirPLFHbX48bICW3vbr0zpNxFFXZpfbzSLtfVprc4
我们可以使用Base64将其还原为原本的样子:
public static void main(String[] args) { String jwtToken = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoiYWRtaW4iLCJuYW1lIjoiamluemUiLCJpZCI6MSwiZXhwIjo2MTY2NDg2MDgwMCwiaWF0IjoxNjk0MTY0NTcwfQ.yvmirPLFHbX48bICW3vbr0zpNxFFXZpfbzSLtfVprc4 "; String[] split = jwtToken.split("\\."); for (int i = 0; i < split.length - 1; i++) { String s = split[i]; byte[] decode = Base64.getDecoder().decode(s); System.out.println(new String(decode)); } }
解析前面两个部分得到:
可以看到确实是经过Base64加密的JSON格式数据,包括我们的自定义数据也在其中,而我们可以直接使用JWT令牌来作为我们权限校验的核心,我们可以像这样设计我们的系统:
首先用户还是按照正常流程进行登录,只不过用户在登录成功之后,服务端会返回一个JWT令牌用于后续请求使用,由于JWT令牌具有时效性,所以说当过期之后又需要重新登录。就像买票,买完过时就无效了。
所以,我们只需要在后续请求中携带这个Token即可(可以放在Cookie中,也可以放在请求头中)这样服务器就可以直接从Token中解密读取到我们用户的相关信息以及判断用户是否登录过期了。