Detailed explanation of JWT-based token authentication (Java implementation)

Detailed explanation of JWT-based token authentication (Java implementation)

Tips before viewing:

The IDEA version used in this article is ultimate 2019.1, and the JDK version is 1.8.0_141.

1 Introduction

In computer identity authentication, it means token (temporary). The token is actually more popular and can be called a secret code. Before some data transmission, the secret code must be checked first. Different secret codes are authorized for different data operations.

2.JWT

JSON Web Token, JSON Web token, our following example is also based on the token authentication implemented by JWT, the following is a completed JWT string

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1ODMyOTQxNzEsInVzZXJOYW1lIjoidXNlciIsInBhc3N3b3JkIjoiMTExMTExMTEifQ.t6JLktclylpt2s5T_B1KDxYCJALr-fbZsy1J_YT57Jk

It is composed of three parts: header, payload and signature

2.1 header

Consists of two parts

  1. The declaration type is JWT.

  2. Declare the encryption algorithm, use HMAC SHA256

The JWT header part is a JSON object, as shown below

{
	'typ': 'JWT',
	'alg': 'HS256'
}

Encrypt it with Base64, then JWT constitutes the first part.

2.2 payload

The payload part is the main content part of the JWT, and is also a JSON object, composed of three parts

  1. Declaration registered in the standard

  2. Public statement

  3. Private statement

The declaration registered in the standard provides seven default fields.

  1. iss: issuer

  2. exp: expiration time

  3. sub: Subject

  4. aud: user

  5. nbf: Not available before

  6. iat: release time

  7. jti: The JWT ID is used to identify the JWT

Public statement

The public statement can add any information, generally adding user-related information or other necessary information required by the business (sensitive information is not recommended).

Private statement

A private statement is a statement jointly defined by the provider and the consumer (sensitive information is not recommended).

The following example is a sample payload

{
	"sub": "1234567890",
	"name": "userName",
	"admin": true
}

Encrypt it with Base64 to form the second part of JWT.

Note: JWT is unencrypted by default and anyone can interpret its content. Therefore, do not construct private information fields and store confidential information to prevent information leakage.

2.3 signature

The signature hash part is to sign the above two parts of data, and generate a hash through the specified algorithm to ensure that the data will not be tampered with. It consists of three parts:

  1. header (encrypted by Base64)

  2. payload (Base64 encrypted)

  3. secret

The server needs a secret key, which is only stored in the server and cannot be disclosed to users. Then, use the signature algorithm specified in the header (HMAC SHA256 by default) to generate a signature according to the following formula.

HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)

After the signature hash is calculated, the three parts of the JWT header, payload, and signature hash are combined into a string, and each part is separated by "." to form the entire JWT object.

3. Use

The client receives the JWT returned by the server and stores it in Cookie or localStorage.

After that, the client will bring JWT when interacting with the server. If it is stored in a Cookie, it can be automatically sent, but it will not cross domains, so it is generally put in the Header Authorization field of the HTTP request.

Use the format as follows

Authorization: Bearer JWT

The whole process of JWT interaction is shown in the figure below

Insert picture description here

4. Examples

This example only provides Java to implement JWT signature and verification, and the use of http transmission will be added later.

The jar package that pom.xml needs to reference

<dependency>
      <groupId>com.auth0</groupId>
      <artifactId>java-jwt</artifactId>
      <version>3.10.0</version>
    </dependency>

    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-core</artifactId>
      <version>2.10.2</version>
    </dependency>

    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.10.2</version>
    </dependency>

    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-annotations</artifactId>
      <version>2.10.2</version>
    </dependency>

Tool class TokenUtil.java

package token;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class TokenUtil {
    
    

    //token过期时长30分钟
    private static final long EXPIRE_TIME = 30 * 60 * 1000;
    //token私钥
    private static final String TOKEN_SECRET = "abcdefg";

    public static String sign(String userName, String password) {
    
    

        String signData = "";
        //过期时间
        Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
        //私钥及加密算法
        Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
        //设置头信息
        Map<String, Object> header = new HashMap();
        header.put("typ", "JWT");
        header.put("alg", "HS256");

        signData = JWT.create()
                .withHeader(header)
                .withClaim("userName", userName)
                .withClaim("password", password)
                .withExpiresAt(date)
                .sign(algorithm);

        return signData;
    }

    /**
     * @Description token解码校验
     * @param token
     * @return
     * @Create 2020-03-03 by jjy
     */
    public static boolean verfiy(String token) {
    
    

        try {
    
    
            Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
            JWTVerifier jwtVerifier = JWT.require(algorithm).build();
            DecodedJWT decodedJWT = jwtVerifier.verify(token);
            String userName = decodedJWT.getClaim("userName").asString();
            String password = decodedJWT.getClaim("password").asString();
            if(!Test.USERNAME.equals(userName) || !Test.PASSWORD.equals(password)) {
    
    
                return false;
            }
            if(new Date().getTime() > decodedJWT.getExpiresAt().getTime()){
    
    
                return false;
            }
            
        } catch (Exception e) {
    
    
            return false;
        }

        return true;
    }
}

Test class Test.java

package token;

public class Test {
    
    

    public static final String USERNAME = "user";
    public static final String PASSWORD = "11111111";

    public static void main(String[] args) {
    
    
        String token = TokenUtil.sign(USERNAME, PASSWORD);

        System.out.println("加密后的token为:" + token);

        boolean flag = TokenUtil.verfiy(token);

        if(flag){
    
    
            System.out.println("校验成功");
        } else {
    
    
            System.out.println("校验失败");
        }
    }
}

The results are as follows

Insert picture description here

Guess you like

Origin blog.csdn.net/weixin_43611145/article/details/104649851