因为http是无状态的协议,所以每次请求都需要进行用户认证(账户名称和密码),否则http无法识别出是否登录过,所以我们将用户信息存入session,将session保存在Redis中,服务器每次收到请求,先去Redis缓存中查询该用户是否登陆过。虽然相比在数据库中查询信息快了很多,但是还是十分浪费时间和空间。于是我们引入JWT,JWT是存用户信息的字符串,存在于网络上。
JWT
用户登录鉴权
将用户信息存放进token中,token是按照一定规则生成的字符串。官方的规则是JWT
JWT的数据结构
JWT一般是这样一个字符串,分为三个部分,以"."隔开:xxxxx.yyyyy.zzzzz
-
Header:jwt头信息.它是一个描述JWT元数据的Json对象
{ "alg": "HS256", "typ": "JWT" }
-
Payload:有效载荷 包含主体信息(用户信息),也是一个Json对象,除了包含需要传递的数据,还有七个默认的字段供选择。
{ //默认字段 "sub":"主题123", //自定义字段 "name":"java技术爱好者", "isAdmin":"true", "loginTime":"2021-12-05 12:00:03" }
-
Signature:签名哈希 防伪标志。需要指定一个secret,该secret仅仅保存在服务器中
(盐值加密:得到原数据后,将原数据和加密数据一起加密)
JWT流程
- 用户使用账号、密码登录应用,登录的请求发送到Authentication Server。
- Authentication Server进行用户验证,然后创建JWT字符串返回给客户端。
- 客户端请求接口时,在请求头带上JWT。
- Application Server验证JWT合法性,如果合法则继续调用应用接口返回结果。
可以看出与token方式有一些不同的地方,就是不需要依赖redis,用户信息存储在客户端。所以关键在于生成JWT,和解析JWT这两个地方。
怎么使用JWT
引入Maven依赖
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.19.2</version>
</dependency>
Controller层代码
@RestController
@RequestMapping("/jwt")
public class JWTTestController {
@RequestMapping("/test.do")
public Map<String,Object> test(){
HashMap<String,Object> result = new HashMap<>();
List<String> permission = new ArrayList<>();
permission.add("/user/login.do");
permission.add("/logic/logic.do");
String token = JWT.create().withClaim("username","liguocheng")
.withClaim("perms",permission)
.sign(Algorithm.HMAC256("xiaopang"));
result.put("token",token);
return result;
}
@RequestMapping("/resolve.do")
public Map<String,Object> resolve(String token){
JWTVerifier verifier = JWT.require(Algorithm.HMAC256("xiaopang")).build();
DecodedJWT decode = verifier.verify(token);
HashMap<String,Object> map = new HashMap<>();
map.put("perms",decode.getClaim("perms").asList(String.class));
map.put("username",decode.getClaim("username").asString());
return map;
}
}
前端生成token的代码:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
</head>
<body>
</body>
<script>
$.ajax({
url:"/jwt/test.do",
type:"post",
success:function (res) {
var token = res.token;
document.cookie = "token="+token;//js获取当前浏览器保存cookie的方法
}
})
</script>
</html>
另一个页面解析token:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery-cookie/1.4.1/jquery.cookie.min.js"></script>
</head>
<body>
</body>
<script>
$.ajax({
url:"/jwt/resolve.do",
// data:{"token":document.cookie.split("=")[1]},
data:{"token":$.cookie("token")},
success:function (res) {
console.log(res);
}
})
</script>
</html>