JWT java 源码浅析

2019-09-29  本文已影响0人  dwwl

JWT场景优劣:
http://blog.didispace.com/learn-how-to-use-jwt-xjf/

JWT入门教程:
https://www.ruanyifeng.com/blog/2018/07/json_web_token-tutorial.html

JWTUtil.java

package org.inlighting.util;

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

import java.io.UnsupportedEncodingException;
import java.util.Date;

public class JWTUtil {

    // 过期时间5分钟
    private static final long EXPIRE_TIME = 5*60*1000;

    /**
     * 校验token是否正确
     * @param token 密钥
     * @param secret 用户的密码
     * @return 是否正确
     */
    public static boolean verify(String token, String username, String secret) {
        try {
            Algorithm algorithm = Algorithm.HMAC256(secret);
            JWTVerifier verifier = JWT.require(algorithm)
                    .withClaim("username", username)
                    .build();
            DecodedJWT jwt = verifier.verify(token);
            return true;
        } catch (Exception exception) {
            return false;
        }
    }

    /**
     * 获得token中的信息无需secret解密也能获得
     * @return token中包含的用户名
     */
    public static String getUsername(String token) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getClaim("username").asString();
        } catch (JWTDecodeException e) {
            return null;
        }
    }

    /**
     * 生成签名,5min后过期
     * @param username 用户名
     * @param secret 用户的密码
     * @return 加密的token
     */
    public static String sign(String username, String secret) {
        try {
            Date date = new Date(System.currentTimeMillis()+EXPIRE_TIME);
            Algorithm algorithm = Algorithm.HMAC256(secret);
            // 附带username信息
            return JWT.create()
                    .withClaim("username", username)
                    .withExpiresAt(date)
                    .sign(algorithm);
        } catch (UnsupportedEncodingException e) {
            return null;
        }
    }
}

加密过程:
JWT.create().withClaim("username", username).withExpiresAt(date).sign(algorithm)

create()

com.auth0.jwt.JWT#create 
public static JWTCreator.Builder create() {
        return JWTCreator.init();
    }
com.auth0.jwt.JWTCreator#init
static JWTCreator.Builder init() {
    return new Builder();
}
 public static class Builder {
        private final Map<String, Object> payloadClaims;
        private Map<String, Object> headerClaims;

        Builder() {
            this.payloadClaims = new HashMap<>();
            this.headerClaims = new HashMap<>();
        }
        ...
    }

withClaim(key,value)

com.auth0.jwt.JWTCreator.Builder#addClaim 该方法有多个重载形式,即value可为
Boolean Integer Long Double String Date
//其中addClaim方法 将键值对加入到payload里面
public Builder withClaim(String name, String value) throws IllegalArgumentException {
    assertNonNull(name);
    addClaim(name, value);
    return this;
}
//在payload中添加一个键为exp 值为过期时间的键值对
public Builder withExpiresAt(Date expiresAt) {
    addClaim(PublicClaims.EXPIRES_AT, expiresAt);
    return this;
}

sign(algorithm)

com.auth0.jwt.JWTCreator.Builder#sign
//该方法时进行JWTCreator对象的建造,并调用JWTCreator中的方法生成最终的字符串,在这个方法里对向jwt的头添加
//键为alg 值为加密名称和键为typ 值为"JWT",将JWTCreator建造者中的算法对象,表示jwt header的map对象,表示jwt payload的map对象传入JWTCreator 
public String sign(Algorithm algorithm) throws IllegalArgumentException, JWTCreationException {
     if (algorithm == null) {
         throw new IllegalArgumentException("The Algorithm cannot be null.");
     }
     headerClaims.put(PublicClaims.ALGORITHM, algorithm.getName());
     headerClaims.put(PublicClaims.TYPE, "JWT");
     String signingKeyId = algorithm.getSigningKeyId();
     if (signingKeyId != null) {
         withKeyId(signingKeyId);
     }
     return new JWTCreator(algorithm, headerClaims, payloadClaims).sign();
 }
com.auth0.jwt.JWTCreator#sign
//将传入的JWT 的header payload信息进行Base64编码,JWT的signature用算法对header payload组成的字符串进行加密生成签名,拼接其后,这就是最后的结果
private String sign() throws SignatureGenerationException {
    String header = Base64.encodeBase64URLSafeString(headerJson.getBytes(StandardCharsets.UTF_8));
    String payload = Base64.encodeBase64URLSafeString(payloadJson.getBytes(StandardCharsets.UTF_8));
    String content = String.format("%s.%s", header, payload);
    byte[] signatureBytes = algorithm.sign(content.getBytes(StandardCharsets.UTF_8));
    String signature = Base64.encodeBase64URLSafeString((signatureBytes));
    return String.format("%s.%s", content, signature);
}

解密:
JWT.require(algorithm).withClaim("username", username).build()

verifier.verify(json);

 com.auth0.jwt.JWTVerifier#verify


 public DecodedJWT verify(String token) throws JWTVerificationException {
 //JWTParser对jwt解析,由base64解析为原字符串,即jwt对象包含jwt的header和payload信息
        DecodedJWT jwt = JWT.decode(token);
 //判断加密方式是否正确
        verifyAlgorithm(jwt, algorithm);
 //利用构建JWTVerifier对象传入的Algorithm对象,即Algorithm.HMAC256("test123"),对jwt中的header和payload进行加密,判断加密后的得到的签名和当前的是否相等
        algorithm.verify(jwt);
 //进行过期时间等判断
        verifyClaims(jwt, claims);
        return jwt;
    }

    public void verify(DecodedJWT jwt) throws SignatureVerificationException {
        byte[] contentBytes = String.format("%s.%s", jwt.getHeader(), jwt.getPayload()).getBytes(StandardCharsets.UTF_8);
        byte[] signatureBytes = Base64.decodeBase64(jwt.getSignature());

        try {
            boolean valid = crypto.verifySignatureFor(getDescription(), secret, contentBytes, signatureBytes);
            if (!valid) {
                throw new SignatureVerificationException(this);
            }
        } catch (IllegalStateException | InvalidKeyException | NoSuchAlgorithmException e) {
            throw new SignatureVerificationException(this, e);
        }
    }
private void verifyClaims(DecodedJWT jwt, Map<String, Object> claims) throws TokenExpiredException, InvalidClaimException {
    for (Map.Entry<String, Object> entry : claims.entrySet()) {
        switch (entry.getKey()) {
            case PublicClaims.AUDIENCE:
                //noinspection unchecked
                assertValidAudienceClaim(jwt.getAudience(), (List<String>) entry.getValue());
                break;
            case PublicClaims.EXPIRES_AT:
                assertValidDateClaim(jwt.getExpiresAt(), (Long) entry.getValue(), true);
                break;
            case PublicClaims.ISSUED_AT:
                assertValidDateClaim(jwt.getIssuedAt(), (Long) entry.getValue(), false);
                break;
            case PublicClaims.NOT_BEFORE:
                assertValidDateClaim(jwt.getNotBefore(), (Long) entry.getValue(), false);
                break;
            case PublicClaims.ISSUER:
                assertValidStringClaim(entry.getKey(), jwt.getIssuer(), (String) entry.getValue());
                break;
            case PublicClaims.JWT_ID:
                assertValidStringClaim(entry.getKey(), jwt.getId(), (String) entry.getValue());
                break;
            case PublicClaims.SUBJECT:
                assertValidStringClaim(entry.getKey(), jwt.getSubject(), (String) entry.getValue());
                break;
            default:
                assertValidClaim(jwt.getClaim(entry.getKey()), entry.getKey(), entry.getValue());
                break;
        }
    }
}
上一篇下一篇

猜你喜欢

热点阅读