Japanese arch pawn series (chat jwt)

1. Introduction

We know that http is a stateless protocol, that is, for server applications, two http requests are independent of each other. You don't know me, I don't know you.

Then the problem comes. For example, when shopping on an e-commerce website, you need to browse the goods, add the goods to the shopping cart, and place an order for settlement. This puts forward requirements: we need to know who chose commodity a, who added commodity a to the shopping cart, and whose shopping cart is A series of questions, such as, all point to "who", that is, to associate multiple different http requests.

How is it related?

You should have reacted. Login authentication! When a user visits a shopping website, the first thing to do is to provide the user name and password to log in to the shopping website, and then in the place of website navigation, it will usually prompt: Welcome xxx! Right? In this way, shopping websites naturally know the series of "who" mentioned above and who it is

This is described from the perspective of ordinary users. We are programmers and need to describe it from the perspective of technology. You say it's not difficult! No, it is

  • When the user accesses the login interface, query the database according to the user name and password provided by the user

  • If the user exists, the shopping website application server, such as tomcat, generates a session and stores it in the memory of the shopping website application server

  • Return the unique identification sessionId of the session to the client (browser), and the browser stores the sessionId in the cookie

  • After the browser successfully logs in again, every time it initiates an http request, such as selecting goods, adding to the shopping cart, placing orders and settlement, it will bring a sessionId. According to the sessionId, it will tell the server that a series of who is who

  • According to sessionId, the application server of the shopping website naturally knows who is choosing goods, who is adding goods to the shopping cart and who is placing orders

Many different http requests are associated through session s and cookie s, and a series of who is who problems are solved. Perfect! It can't be perfect!

This is the familiar solution of traditional session conversation, but this solution is actually flawed. Let's take a look

  • The session is stored in the server, which needs to consume the memory of the application server. If the website business is good, there are tens of millions or hundreds of millions of users. Does it need to consume a lot of memory to store the session alone?

  • The website is too popular, with high concurrency and large traffic. One application server can't carry it. Deploy the cluster scheme, such as adding website application servers a, b and c. Sessions are generated internally by the application server. The user logs in at service node A. if the next request reaches service node b, how does node b know that the user has logged in?

  • The session sessionId is stored in the browser cookie, right? What about CSRF (Cross Site Request Forgery)?

  • In the era of mobile Internet, everyone uses smart phones and plays various app s. What if there is no browser and cookie s are not supported?

  • In the era of distributed and micro services, different applications call each other. Service a does not know the session of service b. what should I do?

To sum up, the biggest disadvantage of the traditional session scheme is that it consumes the memory of the application server and is difficult to support the elastic expansion and contraction of the application.

This is the current popular token scheme in the industry. Next, let's take a look at the token scheme. Here, I will share it with you in combination with jwt.

2. Cases

2.1.token login authentication scheme

In fact, the implementation idea of token login authentication scheme is similar to that of traditional session scheme. After all, token and sessionId are both strings. We analyze it from the operation process of ordinary users

  • The user opens the shopping website and provides the user name and password for login request

  • The website server receives the user login request, queries the database according to the user name and password, and checks whether the user exists

  • If the user exists, a token (a string) is generated according to certain rules

  • Respond the token to the browser, and the user will bring the token in subsequent requests such as selecting goods, adding to the shopping cart, placing orders, etc

  • The website server checks and processes the token, that is, it knows who is who

You see, this is the token scheme. Compared with the traditional session scheme, it is no longer needed

  • Tokens do not need to be stored in the server, that is, they do not consume server memory resources

  • The service continues to be stateless, and the capacity can be expanded or reduced as needed

2.2. What is jwt

The full name of jwt is (json web token). It is an open standard based on json, which is used to transfer declarations between network application environments. The token implemented by jwt is designed to be compact and secure, which is suitable for distributed site single sign on (sso) scenarios.

The token implemented by jwt is mainly composed of three parts Split symbols

eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOiI2NjYiLCJpYXQiOjE2MTg2NDYyNjUsImV4cCI6MTYxOTI1MTA2NX0.uVeXiEhqfhpWAnkiX8glIBE4nOG6o2zaQfRBOC-EiuY
  • header: token, token type, encryption algorithm

  • Load payload: token data, and put some user non sensitive information, such as user id and user name (remember: jwt is user sensitive information that can be decrypted, such as password and mobile phone number, which should not be put in it)

  • Signature: used to verify whether the token is valid and place tampering

2.3.jwt implementation case

2.3.1. Import dependency

<!--jjwt rely on-->
<dependency>
	<groupId>io.jsonwebtoken</groupId>
	<artifactId>jjwt-api</artifactId>
	<version>0.10.7</version>
</dependency>
<dependency>
	<groupId>io.jsonwebtoken</groupId>
	<artifactId>jjwt-impl</artifactId>
	<version>0.10.7</version>
	<scope>runtime</scope>
</dependency>
<dependency>
	<groupId>io.jsonwebtoken</groupId>
	<artifactId>jjwt-jackson</artifactId>
	<version>0.10.7</version>
	<scope>runtime</scope>
</dependency>

2.3.2.jwt tool class

/**
 * token tool
 *
 * @author ThinkPad
 * @version 1.0
 * @date 2021/4/17 14:31
 */
@Slf4j
@Data
public class TokenJwtUtil {

    /**
     * Secret key, default: aaabbbccdddeeeeffggghhhiijjkklllmmm
     */
    private String secret = "aaabbbcccdddeeefffggghhhiiijjjkkklllmmm";
    /**
     * Effective time, one week by default, in seconds
     */
    private Long expirationTime = 604800L;

    /**
     * Generate token
     * @param claims  token data
     * @return
     */
    public String generateToken(Map<String, Object> claims){
        // Generation time, expiration time
        Date createdTime = new Date();
        Date expirationTime = new Date(System.currentTimeMillis() + this.expirationTime * 1000);

        // Secret key
        byte[] keyBytes = this.secret.getBytes();
        SecretKey key = Keys.hmacShaKeyFor(keyBytes);

        // Generate token
       return Jwts.builder()
                .setClaims(claims)
                .setIssuedAt(createdTime)
                .setExpiration(expirationTime)
                .signWith(key, SignatureAlgorithm.HS256)
                .compact();

    }

    /**
     * Verify whether the token is valid
     * @param token
     * @return Valid returns true, invalid returns false
     */
    public Boolean validateToken(String token){
        Date expirationTime = getExpirationDateFromToken(token);
        return !expirationTime.before(new Date());
    }

    /**
     * Get token expiration time
     * @param token
     * @return
     */
    public Date getExpirationDateFromToken(String token) {
        return getClaimsFromToken(token).getExpiration();
    }

    /**
     * Parsing and obtaining token data
     * @param token
     * @return
     */
    public Claims getClaimsFromToken(String token) {

        try{
            return  parser()
                    .setSigningKey(this.secret.getBytes())
                    .parseClaimsJws(token)
                    .getBody();
        }catch (ExpiredJwtException
                | UnsupportedJwtException
                | MalformedJwtException
                | IllegalArgumentException e){
            log.error("analysis token exception occurred", e);
            throw new IllegalArgumentException("Token invalided.");
        }

    }

}

2.3.3. Test use

public static void main(String[] args) {
        TokenJwtUtil tokenJwtUtil = new TokenJwtUtil();

        // 1. Generate token
        Map<String, Object> claims = new HashMap<>();
        claims.put("userId","666");
        String token = tokenJwtUtil.generateToken(claims);
        log.info("prepare token Data:{}", claims);
        log.info("generate token={}",token);

        // 2. Parse token header
        String[] split = token.split("\\.");
        byte[] headBytes = Base64.decodeBase64(split[0]);
        log.info("analysis token Head:{}", new String(headBytes));

        // 3. Parse token data
        byte[] bodyBytes = Base64.decodeBase64(split[1]);
        log.info("analysis token Data:{}", new String(bodyBytes));

        // 4. Parse token signature
        byte[] signatureBytes = Base64.decodeBase64(split[2]);
        log.info("analysis token Signature:{}", new String(signatureBytes));

        // 5. Parse token expiration time
        Date expirationDate = tokenJwtUtil.getExpirationDateFromToken(token);
        log.info("analysis token Expiration time:{}", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(expirationDate));

        // 6. Verify whether the token is valid
        Boolean isValidate = tokenJwtUtil.validateToken(token);
        log.info("check token Valid:{}",isValidate);
}

[com.anan.edu.common.util.Test] - prepare token Data:{userId=666}
[com.anan.edu.common.util.Test] - generate token=eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOiI2NjYiLCJpYXQiOjE2MTg2NDYyNjUsImV4cCI6MTYxOTI1MTA2NX0.uVeXiEhqfhpWAnkiX8glIBE4nOG6o2zaQfRBOC-EiuY
[com.anan.edu.common.util.Test] - analysis token Head:{"alg":"HS256"}
[com.anan.edu.common.util.Test] - analysis token Data:{"userId":"666","iat":1618646265,"exp":1619251065}
[com.anan.edu.common.util.Test] - analysis token Signature:�W��Hj~Vy"_�% 8�ảl�A�A8/���
[com.anan.edu.common.util.Test] - analysis token Expiration date: 2021-04-24 15:57:45
[com.anan.edu.common.util.Test] - check token Valid: true

 

Keywords: Tomcat jwt

Added by smudge on Fri, 04 Mar 2022 20:45:38 +0200