Spring Security (13): JWT token

In this article, let’s understand the knowledge related to JWT tokens. Compared with the traditional JSESSIONID, there is still a big difference. Let’s take a look.

Introduction to JWT token

  • Full name: Json Web Token
  • Features:
    • 自包含, That is, it contains some user information. Compared with the previous random string (JSSESSIONID), after the previous JSSESSIONID cache is lost, the login information is lost, and JWT can retrieve user data through the information contained in it.
    • 密签, Add salt to sign to prevent others from modifying it.
    • 可扩展, You can put any information you want, but generally don’t put sensitive information, because as long as you have a token, you can view the information inside.
  • The application scenario can be called as an interface 凭证, which can be very convenient 实现SSO单点登录(share in the next article).

The composition of JWT

  • First of all, JWT is divided into three parts, for example as follows:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjk1NjJfRkVFREJBQ0siLCJleHAiOjE1OTQ5NzQxNjIsImJlbG9uZ1RvSWQiOjEsImlhdCI6MTU5MjM4MjE2Mn0.wrsn8OiDBAvu8uHhIR01ns2qnP6y-SE0ziEjb8wjxUA

Header

  • There are two parts of information in the header, one is 声明类型, here is JWT; the other is 声明加密的算法, generally using HMAC/SHA256 algorithm.
  • Examples are as follows:
{
    
    
  'typ': 'JWT',
  'alg': 'HS256'
}
  • Then the header is base64 encrypted (the encryption can be symmetrically decrypted) to form the first part of the JWT:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9

Payload

  • The load is 存放有效信息where it is. Including the declarations registered in the standard, public declarations, and private declarations.
  • The declarations registered in the standard include:
    • iss : jwt issuer
    • sub : the user targeted by jwt
    • aud : the party receiving the jwt
    • exp : the expiration time of jwt, this expiration time must be greater than the issuance time
    • nbf : Define the time before the jwt is unavailable.
    • iat : jwt issuance time
    • jti : The unique identity of jwt, which is mainly used as a one-time token to avoid replay attacks.
  • Public statement: Any information can be added to the public statement, generally added 用户的相关信息或其他业务需要的必要信息. It is not recommended to add sensitive information, because this part can be decrypted on the client.
  • Private statement: The private statement is 提供者和消费者所共同定义的声明that it is generally not recommended to store sensitive information, because base64 is symmetrically decrypted, which means that this part of the information can be classified as plaintext information.
  • Examples are as follows:
{
    
    
  "sub": "1000000001",
  "name": "bajie",
  "admin": true
}
  • Then encrypt it with base64 to get the second part of Jwt:
eyJzdWIiOiIxMjk1NjJfRkVFREJBQ0siLCJleHAiOjE1OTQ5NzQxNjIsImJlbG9uZ1RvSWQiOjEsImlhdCI6MTU5MjM4MjE2Mn0

Visa (signature)

  • The third part is a visa information. This visa information consists of three parts: header (after base64 encryption), payload (after base64 encryption), and secret.
  • This part requires the base64-encrypted header and base64-encrypted payload to use .the string formed by the connection, and then 加盐secretcombine and encrypt it through the encryption method declared in the header , and then constitute the third part of jwt:
wrsn8OiDBAvu8uHhIR01ns2qnP6y-SE0ziEjb8wjxUA
  • Finally, the .combination of the three parts constitutes the final jwt.

Application practice

Generally used as login credentials

  • First, the user needs to log in first. After the login is successful, it will be in the success handler 构建一个JWT给到前端(either returned by the response header or directly stuffed into the Cookie).
  • Then every time the user requests the interface 解析验证JWT是否有效.

Actual combat

  • Add dependency
		<dependency>
			<groupId>com.auth0</groupId>
			<artifactId>java-jwt</artifactId>
			<version>3.4.0</version>
		</dependency>
  • Build JWT
		LoginDTO user = (LoginDTO)authentication.getPrincipal();
		user.setUserType("BA");
		Date date = new Date(System.currentTimeMillis() + securityConfig.getTokenExpireTimeInSecond() * 1000);
		
		// 使用head中声明的HMAC256加密方式,再加Salt组合加密
		Algorithm algorithm = Algorithm.HMAC256(securityConfig.getTokenEncryptSalt());

		String token = JWT.create()
				.withSubject(user.getId() + "_" + "BA") // 公有声明
				.withClaim(LoginDTO.BELONG_TO_ID, user.getBelongToId()) // 私有声明
				.withExpiresAt(date) // 设置过期时间
				.withIssuedAt(new Date()) // 构建时间
				.sign(algorithm); // 签证
				
		// 将JWT以响应头的方式返回前端
		response.setHeader(securityConfig.getTokenName(), token);
  • Parse JWT
		DecodedJWT jwt = ((JwtAuthenticationToken)authentication).getToken();

		String subject = jwt.getSubject();
		String userId = subject.split("_")[0];
		String userType = subject.split("_")[1];

		try {
    
    
			Algorithm algorithm = Algorithm.HMAC256(securityConfig.getTokenEncryptSalt());
			JWTVerifier verifier = JWT.require(algorithm)
					.withSubject(subject)
					.build();
			verifier.verify(jwt.getToken());
        } catch (TokenExpiredException e) {
    
    
			throw AuthenticationException.JWT_EXPIRED;
        } catch (Exception e){
    
    
			throw new BadCredentialsException("JWT token verify fail", e);
		}

Guess you like

Origin blog.csdn.net/qq_36221788/article/details/106605529