JWT令牌
- 介绍
会话跟踪
JSON Web Token(JWT)是一个开放的行业标准(RFC 7519),它定义了一种简洁的、自包含的协议格式,用于在通信双方传递json对象,传递的信息经过数字签名可以被验证和信任。
优点:
用 json 作为数据传输,有广泛的通用型,并且体积小,便于传输
不需要在服务器端保存相关信息
Jwt载荷部分可以存储业务相关的信息(非敏感的),例如用户信息、角色等
- 组成
JWT令牌由Header、Payload、Signature三部分组成,每部分中间使用点(.)分隔,比如:xxxxx.yyyyy.zzzzz
第一部分:Header(头),作用:记录令牌类型、签名算法等。 比如
{
"alg":"HS256",//签名算法
"type":"JWT" //类型
}
将上边的内容使用Base64编码,得到一个字符串就是JWT令牌的第一部分。
第二部分:Payload(有效载荷),作用:携带一些用户信息及过期时间等。 比如
{
"id":"1",
"username":"Tom"
}
载荷的意思就是放置东西的容器
将第二部分负载使用Base64编码,得到一个字符串就是JWT令牌的第二部分
第三部分:Signature(签名),作用:防止Token令牌被篡改、确保安全性。比如:计算出来的签名,是一个字符串
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret
)
- 生成JWT
- 引入依赖
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
- 生成JWT代码实现
无论是生成还是校验都需要用到jwts这个工具
@Test
public void genJwt() {
Map<String, Object> claims = new HashMap<>();
claims.put("id", 1);//自定义数据用来放入palyload里面
claims.put("username", "Tom");//自定义数据用来放入palyload里面
String jwt = Jwts.builder()//使用Jwts对象调用builder方法用来生成jwt字符串
.setClaims(claims) //设置携带的数据,放到palyload里面第二步
.signWith(SignatureAlgorithm.HS256, "itheima")//加密的签名算法,签名秘钥(自己设定)
.setExpiration(new Date(System.currentTimeMillis() + 3 * 3600 * 1000))//设置令牌的有效时间
.compact();
System.out.println(jwt);//得到jwt字符串
}
- (校验)解析JWT
@Test
public void parse() {
String jwts="eyJhbGciOiJIUzI1NiJ9.eyJpZCI6MSwiZXhwIjoxNjkxMjE4MTA3LCJ1c2VybmFtZSI6IlRvbSJ9." +
"Rqn2IoYpRueq-wOwYPQEg7nxP__NqBgBJLklDzWij3A";
Claims claims = Jwts.parser() //解析
.setSigningKey("itheima") //设置签名秘钥
.parseClaimsJws(jwts) //jwt令牌
.getBody();//获取令牌中携带的数据
System.out.println(claims);
}
- 登录-生成令牌
- 第一步,在登录成功之后,生成JWT令牌并返回给浏览器
步骤:
引入JWT工具类
登录完成后,调用工具类生成JWT令牌并返回
- . 引入JWT工具类
package com.itheima.util;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.Date;
import java.util.Map;
public class JwtUtils {
private static String signKey = "itheima";//给秘钥
private static Long expire = 43200000L;//设置令牌作用时间
/**
* 生成JWT令牌
* @param claims JWT第二部分负载 payload 中存储的内容
* @return
*/
public static String generateJwt(Map<String, Object> claims){
String jwt = Jwts.builder()
.addClaims(claims)
.signWith(SignatureAlgorithm.HS256, signKey)
.setExpiration(new Date(System.currentTimeMillis() + expire))
.compact();
return jwt;
}
/**
* 解析JWT令牌
* @param jwt JWT令牌
* @return JWT第二部分负载 payload 中存储的内容
*/
public static Claims parseJWT(String jwt){
Claims claims = Jwts.parser()
.setSigningKey(signKey)
.parseClaimsJws(jwt)
.getBody();
return claims;
}
}
- .登录成功,生成JWT令牌并返回
@RestController
public class LoginController {
@Autowired
private EmpService empService;
@PostMapping("/login")
public Result Login(@RequestBody Emp emp) {
Emp loginemp = empService.Login(emp);
if (loginemp == null) {
return Result.error("用户名或密码错误");
}
//返回结果
//生成令牌
Map<String, Object> claims = new HashMap<>();//用来存储令牌要携带的数据
claims.put("id", loginemp.getId());
claims.put("username", loginemp.getUsername());
//生成令牌
String jwt = JwtUtils.generateJwt(claims);
return Result.success(jwt);//返回给前端
}
}