JWT

JWT(JSON Web Token) is an open jSON-based standard implemented to pass declarations between network application environments.

Example Login Procedure

Here is a personal collation of some information, the need of friends can be directly click to receive.

Java Basics

22 Java Architect Core books

Learning routes and materials from 0 to 1Java

1000+ questions from 2021

composition

What exactly does a JWT look like? JWT is made up of three pieces of information. Use these three pieces of information text. The links together make up the JWT string. Something like this:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cB ab30RMHrHDcEfxjoYZgeFONFh7HgQCopy the code

The element

header

The header of the JWT carries two pieces of information:

  • Declare type, in this case JWT;
  • Declare the encryption algorithm, usually directly use HMAC SHA256;
  • The complete header looks like this JSON:
{
  'typ': 'JWT',
  'alg': 'HS256'
}

Copy the code

Using Base64 encryption forms the first part.

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9

Copy the code

Playload (emphasis)

Payload is the place where valid information is stored, and this valid information consists of three parts:

  • A declaration of registration in the standard;
  • A public statement;
  • A private declaration;

The declaration of registration in the standard (recommended but not mandatory) includes the following parts:

  • Iss: JWT issuer;
  • Sub: the user JWT is targeting;
  • Aud: the side receiving JWT;
  • Exp: expiration time of JWT. This expiration time must be longer than the issue time.
  • NBF: defines the time before the JWT is unavailable;
  • Iat: issue time of JWT;
  • The unique identifier of JWT is mainly used as a one-time token to avoid replay attacks.

Public declaration part: Public declaration part can add any information, generally add user information or other necessary information required by the business, but it is not recommended to add sensitive information, because this part can be decrypted on the client.

Private declaration part: A private declaration is a declaration defined by both the provider and the consumer. 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.

Define a payload:

{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true
}

Copy the code

It is then base64 encrypted to get the second part of Jwt:

eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9

Copy the code

signature

The third part of the JWT is a visa information, which consists of three parts:

var encodedString = base64UrlEncode(header) + '.' + base64UrlEncode(payload); Var signature = HMACSHA256(encodedString, 'key '); After encryption, the signature information is obtained. TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQCopy the code

JWT final format

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cB ab30RMHrHDcEfxjoYZgeFONFh7HgQCopy the code

Secret is used for JWT signing and JWT validation, so it should not be revealed in any scenario.

The element

SpringBoot integration with JWT

Introduction of depend on

<! --token--> <! Java - JWT </artifactId> </dependency> JWT </artifactId>Copy the code

Create the JWT utility class

Note the configuration file injection for static properties:

package com.neuq.common.util; import com.auth0.jwt.JWT; import com.auth0.jwt.algorithms.Algorithm; import com.auth0.jwt.exceptions.TokenExpiredException; import com.neuq.common.exception.ApiException; import com.neuq.common.response.ResultInfo; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; import java.util.Date; /** * @Author: xiang * @Date: 2021/5/11 21:11 * <p> * JwtToken Generated tool class * JWT token format: header.paypay. signature * Header format (algorithm, token type). Default: {"alg": "HS512","typ": "JWT"} * payload = "payload"  * HMACSHA512(base64UrlEncode(header) + "." +base64UrlEncode(payload),secret) */ @Component @configurationProperties (prefix = "JWT ") public class JWTUtils {// Define the token return header public static String header; // Token prefix public static String tokenPrefix; Public static String secret; Public static long expireTime; Public static final String USER_LOGIN_TOKEN = "USER_LOGIN_TOKEN"; public static final String USER_LOGIN_TOKEN = "USER_LOGIN_TOKEN"; public void setHeader(String header) { JWTUtils.header = header; } public void setTokenPrefix(String tokenPrefix) { JWTUtils.tokenPrefix = tokenPrefix; } public void setSecret(String secret) { JWTUtils.secret = secret; } public void setExpireTime(int expireTimeInt) { JWTUtils.expireTime = expireTimeInt*1000L*60; } /** * createToken * @param sub * @return */ public static String createToken(String sub){return tokenPrefix + JWT.create() .withSubject(sub) .withExpiresAt(new Date(System.currentTimeMillis() + expireTime)) .sign(Algorithm.HMAC512(secret)); } /** * public static String validateToken(String token){try {return JWT.require(Algorithm.HMAC512(secret)) .build() .verify(token.replace(tokenPrefix, "")) .getSubject(); } catch (TokenExpiredException e){throw new ApiException(resultInfo. unauthorized(" Token has expired ")); } catch (Exception e){throw new ApiException(resultInfo. unauthorized(" Token authentication failed ")); Public static Boolean isNeedUpdate(String token){// Obtain the token expiration Date  expiresAt = null; try { expiresAt = JWT.require(Algorithm.HMAC512(secret)) .build() .verify(token.replace(tokenPrefix, "")) .getExpiresAt(); } catch (TokenExpiredException e){ return true; } catch (Exception e){throw new ApiException(resultInfo. unauthorized(" Token authentication failed ")); Return (expiresat.getTime () -system.currentTimemillis ()) < (expireTime>>1); }}Copy the code

Yaml attribute configuration

JWT: header: "Authorization" #token return header tokenPrefix: "Bearer "#token prefix secret:" qWERtyuiop7418520 "# key expireTime: 1 # Token validity period (minutes) More than one hour is recommendedCopy the code

Login method Returns user information saved in token

@ Override public Map < String, Object > login User (User) {/ / phone is the only sign except the id Need to check the if (user getPhone () = = null | | User.getphone ().equals("")) throw new ApiException(" phone number is invalid "); User selectUser = userDao.selectUserByPhone(user.getPhone()); If (selectUser == null) {// Register user int count = userdao.insertUser (user); If (count < 1) throw new ApiException (ResultInfo. ServiceUnavailable (" registered exception ")); } String token = jwTutils.createToken (selectUser.getUserId().toString()); Map<String,Object> map = new HashMap<>(); map.put("user",selectUser); map.put("token",token); return map; }Copy the code

Note that the token is saved to Http headers

@GetMapping("/login") public ResultInfo login(User user, HttpServletResponse response) { Map<String, Object> map = userService.login(user); Responsetheader (jwtutils.user_login_token, (String) map.get("token")); response.setheader (jwtutils.user_login_token, (String) map.get("token")); response.setheader (jwtutils.user_login_token, (String) map.get("token")); return ResultInfo.success((User)map.get("user")); }Copy the code

The interceptor validates the token on each request

/** * @Author: xiang * @Date: 2021/5/7 20:56 * <p> * Interceptor: */ public class UserLoginInterceptor implements HandlerInterceptor {@override public Boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object Handler) throws Exception {// Obtain the token in the HTTP header. String Token = Request.getheader (jwtutils.user_login_token); / / token does not exist the if (token = = null | | token. Equals (" ")) throw new ApiException (" please login first "); // validateToken String sub = jwtutils.validatetoken (token); If (sub = = null | | sub. Equals (" ")) throw new ApiException (ResultInfo. Unauthorized (" token authentication failed ")); If (jwtutils.isNEEDupDate (token)){String newToken = jwtutils.createToken (sub); String newToken = jwtutils.createToken (sub); response.setHeader(JWTUtils.USER_LOGIN_TOKEN,newToken); } return true; }}Copy the code
@configuration@ComponentScan (basePackages = "com.neuq.mon ") // Global exception handling classes need to be scanned to public class WebMvcConfig implements WebMvcConfigurer {/** * register custom interceptor ** @param registry */ @override public void addInterceptors(InterceptorRegistry) registry) { registry.addInterceptor(new UserLoginInterceptor()) .addPathPatterns("/user/**") .addPathPatterns("/userInfo/**") .excludePathPatterns("/user/login"); // Open the login path}}Copy the code

Single sign-on (sso)

Store token or a unique identifier UUID= uuid.randomuuid ().tostring () in Cookie (not in Http header) and set path to entire project root path /*; This unique identifier is often cached in the server as key, user information as value!!

The last

Thank you big guy can see the end, think the article is helpful to you remember to like!