一、简介/概述:
用户登录成功后,系统会自动下发JWT令牌,然后在后续的每次请求中,浏览器都需要在请求头header中携带到服务端,请求头的名称为 Authorization,值为 登录时下发的JWT令牌。如果检测到用户未登录,则http响应状态码为401
二、优点
- 承载业务数据,减少后续请求查询数据库的次数
- 防篡改,保证信息的合法性和有效性
token是令牌的意思,java对Jason数据进行编码(使用Base64进行编码),因为Base64可以编码,也可以解码,所以在payload部分不能存放密码信息
三、JWT令牌的生成和校验(基于java代码)
/**
* 生成JWT
*/
@Test
public void testGenJwt() {
Map<String, Object> claims = new HashMap<>();
claims.put("id", 1);
claims.put("name", "tom");
String jwt = Jwts.builder()
.signWith(SignatureAlgorithm.HS256, "itheima")//签名算法
.setClaims(claims) //自定义内容(载荷)
.setExpiration(new Date(System.currentTimeMillis() + 3600 * 1000))//设置有效期为1h
.compact();
System.out.println(jwt);
}
代码解析:
.Jwts.builder():这是 JJWT 库中用于构建 JWT 的起始方法,它返回一个JwtBuilder对象,后续可以通过链式调用一系列方法来配置 JWT 的各个属性。
.signWith(SignatureAlgorithm.HS256, “itheima”):指定 JWT 的签名算法为 HS256(HMAC – SHA256),并设置签名密钥为字符串”itheima”。签名用于验证 JWT 的完整性和真实性,防止令牌被篡改。
.setClaims(claims):这里的claims是一个Map类型(通常是HashMap),用于存储自定义的负载信息,比如用户 ID、用户名、权限等。这些信息会被编码到 JWT 的负载部分。
.setExpiration(new Date(System.currentTimeMillis() + 3600 * 1000)):设置 JWT 的过期时间。代码中计算了从当前时间开始往后 1 小时(3600 * 1000毫秒)的时间点作为过期时间。
.compact():该方法将前面配置好的 JWT 构建成一个紧凑的字符串形式,即最终生成的 JWT 令牌,它是由三部分(头部、负载、签名)经过 Base64Url 编码后,用.连接起来的字符串。
/**
解析JWT令牌
**/
@Test
public void parseJwt() {
Claims claims = Jwts.parser()
.setSigningKey("itheima") //指定签名秘钥
.parseClaimsJws("eyJhbGciOiJIUzI1NiJ9.eyJpZCI6MSwiZXhwIjoxNjU1OTk1NTE3LCJ1c2VybmFtZSI6InRvbSJ9.EUTfeqPkGslekdKBezcWCe7a7xbcllwB1MXllccTMwo") //解析令牌
.getBody();
System.out.println(claims);
}
代码解析
.Jwts.parser()
:这是 JJWT 库中用于开始解析 JWT 的方法,返回一个JwtParser
对象。
.setSigningKey("itheima")
:设置用于验证 JWT 签名的密钥为"itheima"
。在生成 JWT 时会使用一个密钥进行签名,解析时必须使用相同的密钥才能成功验证。
.parseClaimsJws("eyJhbGciOiJIUzI1NiJ9.eyJpZCI6MSwiZXhwIjoxNjU1OTk1NTE3LCJ1c2VybmFtZSI6InRvbSJ9.EUTfeqPkGslekdKBezcWCe7a7xbcllwB1MXllccTMwo")
:尝试解析给定的 JWT 字符串。这里的 JWT 字符串由三部分组成,分别是头部、负载和签名,以.
分隔。如果签名验证通过,该方法会返回一个包含 JWT 信息的Jws<Claims>
对象。
.getBody()
:从Jws<Claims>
对象中获取 JWT 的负载部分,负载中包含了自定义的用户信息等内容,这里将其赋值给claims
变量,claims
是一个Claims
类型的对象,本质上是一个Map<String, Object>
,可以通过键来获取对应的值。
四、思路
– 令牌生成:登录成功后,生成JWT令牌,并返回给前端。
– 令牌校验:在请求到达服务端后,对令牌进行统一拦截、校验。
五、实战
– 引入JWT令牌操作工具类。
– 登录完成后,调用工具类生成JWT令牌,并返回。
@Autowired
private EmpService empService;
@PostMapping("/login")
public Result login(@RequestBody Emp emp) {
Emp e = empService.login(emp);
if (e != null) { //用户名密码正确
Map<String, Object> claims = new HashMap<>();
claims.put("id", e.getId());
claims.put("username", e.getUsername());
claims.put("name", e.getName());
//生成JWT令牌
String jwt = JwtUtils.generateJwt(claims);
//JwtUtils是已定义的工具类,调用它的令牌生成方法
return Result.success(jwt);
}
return Result.error("用户名或密码错误");
}
前端浏览器会将返回的JWT令牌存储到浏览器本地,在后续的请求中在请求头中携带JWT令牌
在请求头中的token携带