JWT used by Java open source tool library

foreword

The translation of the official website introduction is as follows:

What are JWTs?

    JSON Web Token (JWT) is an open standard ( RFC 7519 ) that defines a compact and self-contained way to securely transmit information between parties as JSON objects. This information can be verified and trusted because it is done with a digital signature. jwt can be signed with a secret key (using the HMAC algorithm) or with a public/private key pair using RSA or ECDSA.

    While JWT can also be encrypted to provide confidentiality between parties, focus on signing Tokens. Signed tokens can verify the integrity of the claims contained within them, while encrypted tokens can hide those claims from other parties. When signing using a public/private key pair, the signature also proves that only the party holding the private key is the one who signed it.

When to use JWT?

Authorization: This is the most common scenario for using JWT. Once the user is logged in, every subsequent request will include the JWT, allowing the user to access the routes, services, and resources allowed by that token. Single sign-on is a feature where JWT is widely used these days because it has little overhead and can be easily used across different realms.

Information Exchange: JSON Web Tokens are a great way to securely transfer information between two parties. Because JWTs can be signed, for example, with a public/private key pair, you can be sure the sender is who they say they are. Also, since the signature is calculated using the header and payload, you can also verify that the content has not been tampered with.

It can be seen that JWT is often used in identity authentication, and it is also the most popular cross-domain authentication solution.

Traditional stand-alone back-end services often use Session to save user login status information, but the problem with this model is that, when encountering non-browsers such as WeChat applets, Session cannot be used to save user information, and in multi-machine ( server cluster) or a service-oriented cross-domain system, a simple Session cannot handle this situation.

JWT is a flexible solution for the above. It is a stateless Token that saves data through the client, but the server does not save session data at all, and each request is sent back to the server.

There are many JWT implementation libraries, and there are corresponding libraries for different programming languages. For details, please refer to the official website . There are several types of java, and the top one on the official website is the open source library java-jwt .

github: https://github.com/auth0/java-jwt

The pom dependencies are as follows:

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

1. JWT specification

JWT consists of three parts: Header , Payload , and Signature , and the three parts are separated by dots (.).

1.1 Header head

The header usually consists of two parts: the type of Token, which is JWT, and the signature algorithm being used, such as HMAC SHA256 or RSA.

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

This part of json data is usually encoded by Base64 into a string of strings as the header of JWT, which is the first part, which can be realized through the js function btoa

btoa('{"alg": "HS256","typ": "JWT"}')

get

eyJhbGciOiAiSFMyNTYiLCJ0eXAiOiAiSldUIn0=

1.2 Payload

This is the core part of JWT and the main body of data transmission, including the data to be transmitted, and some defined fields, which can be called Claims .

Here are some common claims:

Abbreviation full name meaning
iss Issuer Issuer
sub Subject main body
aud Audience (receiving) target party
exp Expiration Time Expiration
nbf Not Before Earlier than the defined time JWTcannot be accepted for processing
iat Issued At JWTTimestamp when issued
jti JWT ID JWTunique identifier of

example:

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

It will also be base64 encoded as a string as the second part of the JWT

btoa('{"sub": "1234567890","name": "John Doe","admin": true,"exp": 1613297468168}')

get

eyJzdWIiOiAiMTIzNDU2Nzg5MCIsIm5hbWUiOiAiSm9obiBEb2UiLCJhZG1pbiI6IHRydWUsImV4cCI6IDE2MTMyOTc0NjgxNjh9

1.3 Signature signature

The function of the signature is to protect the integrity of the Claims (or data encryption) and ensure that the Claims are not tampered with (or not cracked) during JWT transmission.

For example: use the HMAC SHA256 algorithm to encrypt the header and payload in the following way to get a signature. Both the header and the payload are transmitted in plain text via base64 encoding, and the signature is used to ensure that it has not been tampered with. Even if the plain text part is obtained, the corresponding encryption algorithm is known, but it is difficult to forge the signature without the secret key.

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

Two, Java implementation

2.1 create

  • basic use

    Tokens can be easily generated using the API provided by java-jwt

    
    String userId = "10086";
    LocalDateTime now = LocalDateTime.now();
    long expireDays = 7;
    String s= ""; 
    
    Date startDate = localDateTimeToDate(now);
    Date endDate = localDateTimeToDate(now.plusDays(expireDays));
    
    Algorithm algorithm = Algorithm.HMAC256(s);
    Map<String, Object> header = new HashMap<>();
    header.put("alg", "HS256");
    header.put("typ", "JWT");
    
    String token = JWT.create()
            .withHeader(header)
            .withAudience(userId)
            .withIssuedAt(startDate)
            .withExpiresAt(endDate)
            .withClaim("test", "test values")
            .sign(algorithm);
    
    System.out.println(token);
    // eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiIxMDA4NiIsInRlc3QiOiJ0ZXN0IHZhbHVlcyIsImV4cCI6MTY3NDU2NzAxMSwiaWF0IjoxNjczOTYyMjExfQ.GSpwAX6WG3RMplu4TdSsYLWTjNlqGh3KC-ifhA-_x50
    
  • Change the encryption algorithm

    java-jwt has many built-in encryption algorithms, for example: RSA256 can be used

    KeyPairGenerator rsa = KeyPairGenerator.getInstance("RSA");
    rsa.initialize(512);
    KeyPair keyPair = rsa.generateKeyPair();
    PublicKey publicKey = keyPair.getPublic();
    PrivateKey privateKey = keyPair.getPrivate();
    System.out.println(Base64.getEncoder().encodeToString(publicKey.getEncoded()));
    System.out.println(Base64.getEncoder().encodeToString(privateKey.getEncoded()));
    Algorithm rsa256Algorithm = Algorithm.RSA256((RSAPublicKey) publicKey, (RSAPrivateKey) privateKey);
    

2.2 Decryption

DecodedJWT jwt = JWT.require(algorithm).build().verify(token);

String jwtAlgorithm = jwt.getAlgorithm();
String jwtId = jwt.getAudience().get(0);
Map<String, Claim> claims = jwt.getClaims();

System.out.printf("%s \n%s \n%s%n", jwtAlgorithm, jwtId, claims);

2.3 Validation

  • time check

    A JWT token can contain some date-related information for validating it:

    • The token is an issued token: "iat" < NOW
    • The token has not expired: "exp" > NOW
    • The token is already used: "nbf" < NOW

    The verification of the date is automatically performed when verifying the token. If the verification fails, a JWTVerificationException will be thrown .

    The acceptLeeway method in the verification method is to set the leeway attribute. By viewing the source code, you can find that it is a second value with room for it.

    private boolean assertInstantIsFuture(Instant claimVal, long leeway, Instant now) {
          
          
        return claimVal == null || !now.minus(Duration.ofSeconds(leeway)).isAfter(claimVal);
    }
    
    private boolean assertInstantIsPast(Instant claimVal, long leeway, Instant now) {
          
          
        return claimVal == null || !now.plus(Duration.ofSeconds(leeway)).isBefore(claimVal);
    }
    
    JWTVerifier verifier = JWT.require(algorithm)
            .acceptLeeway(1)
            .build();
    verifier.verify(token);
    
  • claim verification

    In addition to the above-mentioned time verification, you can also verify the transmitted information, that is, the claim, and throw an exception JWTVerificationException if it fails

    JWTVerifier verifier = JWT.require(algorithm)
                    .acceptLeeway(1)
                    .withClaim("test", "123")
                    .withClaimPresence("test")
                    .build();
    verifier.verify(token);
    

reference

  1. https://jwt.io/introduction
  2. JWT comprehensive interpretation, detailed use steps

Guess you like

Origin blog.csdn.net/qq_23091073/article/details/128721782