JWT介绍

概念

JWT无状态,Shiro有状态,可以结合

用户权限有以下几个

  1. Authentication:用户认证
  2. Authorization:用户授权

因为http是无状态的,每次请求都是无状态的。

当用户登录后,他的下个请求不会包含当前状态,所以只能重新认证

但我们希望,用户登录后的每个http请求都能保存他的登录状态

目前主要用token和session两种方式

JWT和Token区别

基于Session的用户认证

  1. 用户输入登录信息
  2. 服务器校验成功后并创建一个session,然后存到数据库【也就是说session存在数据库的服务器的
  3. 服务器为用户生成一个sessionId,将据有sessionId的cookie放在用户浏览器
  4. 后续请求中,用户每次请求都传送cookie?会根据数据库校验sessionId,有效则接受
  5. 一旦用户注销应用程序,会话将在服务端和客户端被销毁

基于token的用户认证(最常用的是jwt)

  1. 用户输入登录信息
  2. 服务器校验信息是否正确,并返回已签名的token
  3. token存储在客户端,并返回已签名的token
  4. 之后http请求都将token添加到请求头里面
  5. 服务器解码jwt,如果令牌有效,则接受请求
  6. 一旦用户注销,令牌将在客户端被销毁【因为令牌是无状态的。后端服务器不需要保存令牌】

JWT和Session对比

  • JWT优点:如果应用程序分布式部署,session需要做多机共享,需要存在redis,而JWT不用
  • JWT优点:无状态,服务器不需要存储任何信息
  • JWT缺点:用的base64编码,等于没加密,而session信息是存在服务器的,所以session安全一些
  • JWT缺点:性能,服务器必须解码,并且每次请求都需要把jwt放在里面
  • JWT缺点:无法废弃,续签麻烦

JWT在SpringBoot中使用

<!--jwt-->
<dependency>
   <groupId>io.jsonwebtoken</groupId>
   <artifactId>jjwt</artifactId>
   <version>0.9.1</version>
</dependency>

重要特性:存储信息越多,JWT字符串长度越长,JWT长度越短越好

重要bug:只要设置了setClaims,jwt就会自动把setExpiration放入setClaims中。所以建议直接用claim(String,Object),把map放到Object里面去即可

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
public static void main(String[] args) {
   // 创建一个jwtToekn
   JwtBuilder builder = Jwts.builder().setId("888")
          .setSubject(new String("mcc"))
          .setIssuedAt(new Date())       // 签发时间
          .signWith(SignatureAlgorithm.HS256,"itcast") // 签名加密算法和私钥信息
          .claim("companyId",new String("hwts")) // 自己指定的信息
          .claim("schoolName",new String("USTC")); // claim是一个<k,v>结构
   String token = builder.compact(); // compact就是方法会把它变成字符串
   System.out.println(token);
   System.out.println(token.length());

   // 解析token
   Claims claims = Jwts.parser().setSigningKey("itcast")
          .parseClaimsJws(token).getBody();// getBody之前是所有信息
   // 输出信息
   System.out.println(claims.getId());
   System.out.println(claims.getSubject());
   System.out.println(claims.getIssuedAt());
   System.out.println(claims.get("companyId"));
}