关于jwt的类dsl语义封装

说明:

  • 背景: 对于项目中原来自我封装的jwt工具类不尽如意, 相对稍显笨重, 另工具类需要告诉使用者如何使用,每人都要讲一遍比较麻烦, 因此, 重新封装了jwt工具类, 使其自带解释. 借鉴dsl语义, 借鉴alibaba cola状态机设计.
  • jwt中有一些必要参数,不分先后都可以,如此,在dsl调用链里就可以人为指定一种顺序(没有顺序本身也就意味着任何一种顺序都可以)

目录树

关于jwt的类dsl语义封装_第1张图片

使用示例

public static void main(String[] args) throws InterruptedException, IOException {
        String key = UUID.randomUUID().toString();
        long l = LocalDateTime.now().plusSeconds(10).toInstant(ZoneOffset.ofHours(8)).toEpochMilli();
        Date expireAt = new Date(l);
        Operator operator2 = JwtUtil.builder().secret(key).audience("admin").issure("admin").expireAt(expireAt).generator().build();
        System.out.println(operator2);
        TimeUnit.SECONDS.sleep(2);
        Operator operator3 = JwtUtil.builder().secret(key).audience("admin").issure("admin").token(operator2.getToken()).verify().build();
        System.out.println(operator3);
    }

可以看到上述的代码好似和我们熟知建造者模式类似, 但是在编译器里写的是否, 会发现, 你做了第一步之后,下一步是什么,是完全自动提示的, 不需要再有额外的文档阐述, 我觉得这种是非常好的,程序自带解释.
下面是idea的自动提示截图:
关于jwt的类dsl语义封装_第2张图片
关于jwt的类dsl语义封装_第3张图片
关于jwt的类dsl语义封装_第4张图片
关于jwt的类dsl语义封装_第5张图片
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
可以看到整个JwtUtil工具类已有了自我解释能力,我非常欣赏这样的工具包,就如cola的状态及,okhttp一样, 用起来是非常好用的.

整个源码如下,目前未上传github,后续会整理整套好用的工具包放入.


import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.IOException;
import java.util.*;

public class JwtUtil implements Builder, Secret, Audience, Issure, Token, ExpireAt, Generator, Verify, Operator {
    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

    private static final String BEARER = "Bearer ";

    private String secret;
    private String[] audience;
    private String issure;
    private String token;
    private Date expireAt;
    private String jwtId;
    private String keyId;
    private Date issuedAt;
    private final Map payload = new HashMap<>();
    private JWTVerifier jwtVerifier;
    private DecodedJWT decodedJWT;

    private JwtUtil() {

    }

    public static Builder builder() {
        return new JwtUtil();
    }

    @Override
    public Secret secret(String secret) {
        this.secret = secret;
        return this;
    }

    @Override
    public Audience audience(String... audience) {
        this.audience = audience;
        return this;
    }

    @Override
    public Issure issure(String issure) {
        this.issure = issure;
        return this;
    }

    @Override
    public Token token(String token) {
        this.token = token;
        return this;
    }

    @Override
    public ExpireAt expireAt(Date expireAt) {
        this.expireAt = expireAt;
        return this;
    }

    @Override
    public Generator generator(Map payload) {
        JWTCreator.Builder builder = JWT.create();
        this.issuedAt = new Date();
        this.jwtId = UUID.randomUUID().toString().toUpperCase();
        this.keyId = UUID.randomUUID().toString().toUpperCase();
        if (payload != null) {
            this.payload.putAll(payload);
        }
        builder
                .withExpiresAt(this.expireAt)
                .withIssuedAt(this.issuedAt)
                .withIssuer(this.issure)
                .withAudience(this.audience)
                .withJWTId(this.jwtId)
                .withKeyId(this.keyId)
                .withPayload(this.payload)
        ;
        this.token = BEARER+builder.sign(Algorithm.HMAC256(this.secret));
        this.payload.put("iss", this.issure);
        this.payload.put("aud", this.audience);
        this.payload.put("exp", this.expireAt.getTime() / 1000);
        this.payload.put("jti", this.jwtId);
        this.payload.put("iat", this.issuedAt.getTime()/1000);
        return this;
    }

    @Override
    public Generator generator() {
        return this.generator(null);
    }

    @Override
    public Verify verify() throws IOException {
        if (this.jwtVerifier == null) {
            this.jwtVerifier = JWT.require(Algorithm.HMAC256(secret)).build();

        }
        if (this.decodedJWT == null) {
            this.decodedJWT = jwtVerifier.verify(token.replace(BEARER,""));
            this.audience = this.decodedJWT.getAudience().toArray(new String[0]);
            this.issure = this.decodedJWT.getIssuer();
            this.issuedAt = this.decodedJWT.getIssuedAt();
            this.expireAt = this.decodedJWT.getExpiresAt();
            this.jwtId = this.decodedJWT.getId();
            this.keyId = this.decodedJWT.getKeyId();
            this.payload.putAll(OBJECT_MAPPER.readValue(Base64.getUrlDecoder().decode(this.decodedJWT.getPayload()), new TypeReference>() {
            }));
        }
        return this;
    }

    @Override
    public Operator build() {
        return this;
    }

    @Override
    public String getSecret() {
        return this.secret;
    }

    @Override
    public String[] getAudience() {
        return this.audience;
    }

    @Override
    public String getIssure() {
        return this.issure;
    }

    @Override
    public String getToken() {
        return this.token;
    }

    @Override
    public Date getExpireAt() {
        return this.expireAt;
    }

    @Override
    public String getJwtId() {
        return this.jwtId;
    }

    @Override
    public String getKeyId() {
        return this.keyId;
    }

    @Override
    public Date getIssuedAt() {
        return this.issuedAt;
    }

    @Override
    public Map getPayload() {
        return this.payload;
    }

    @Override
    public boolean getClaimAsBool(String name) {
        String claimAsString = this.getClaimAsString(name);
        if (claimAsString == null) return false;
        return Boolean.parseBoolean(claimAsString);
    }

    @Override
    public int getClaimAsInt(String name) {
        String claimAsString = this.getClaimAsString(name);
        if (claimAsString == null) return 0;
        return Integer.parseInt(claimAsString);
    }

    @Override
    public long getClaimAsLong(String name) {
        String claimAsString = this.getClaimAsString(name);
        if (claimAsString == null) return 0;
        return Long.parseLong(claimAsString);
    }

    @Override
    public Object getClaim(String name) {
        return this.payload.get(name);
    }

    @Override
    public String getClaimAsString(String name) {
        if (name == null) return null;
        return String.valueOf(this.getClaim(name));
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("jwt:{");
        if (this.audience == null) {
            sb.append("audience=null");
        } else {
            sb.append("audience=").append(String.join(",",this.audience));
        }
        sb.append(",issure=").append(this.issure);
        sb.append(",token=").append(this.token);
        sb.append(",expireAt=").append(this.expireAt);
        sb.append(",jwtId=").append(this.jwtId);
        sb.append(",keyId=").append(this.keyId);
        sb.append(",issuedAt=").append(this.issuedAt);
        sb.append(",payload={");
        this.payload.forEach((k, v) -> {
            if (v.getClass().isArray()){
                if (Objects.equals(v.getClass().getComponentType().getTypeName(), String.class.getTypeName())){
                    String[] vv = (String[]) v;
                    sb.append(k).append("=").append(String.join(",", vv)).append(",");
                }else {
                    sb.append(k).append("=").append(v).append(",");
                }
            }else {
                sb.append(k).append("=").append(v).append(",");
            }
        });
        if (sb.charAt(sb.length() - 1) == ',') {
            sb.deleteCharAt(sb.length() - 1);
        }
        sb.append("}");
        sb.append("}");
        return sb.toString();
    }

}


import lombok.NonNull;

public interface Audience {
    Issure issure(@NonNull String issure);
}

import lombok.NonNull;

public interface Builder {
    Secret secret(@NonNull String secret);
}

import java.util.Map;

public interface ExpireAt {
    Generator generator(Map payload);

    Generator generator();
}

public interface Generator {
    Operator build();
}

import lombok.NonNull;

import java.util.Date;

public interface Issure {
    Token token(@NonNull String token);

    ExpireAt expireAt(@NonNull Date expireAt);
}


public interface Operator {

    String getSecret();

    String[] getAudience();

    String getIssure();

    String getToken();

    Date getExpireAt();

    String getJwtId();

    String getKeyId();

    Date getIssuedAt();

    Map getPayload();

    boolean getClaimAsBool(String name);

    int getClaimAsInt(String name);

    long getClaimAsLong(String name);

    Object getClaim(String name);

    String getClaimAsString(String name);
}

import lombok.NonNull;

public interface Secret {
    Audience audience(@NonNull String... audience);
}


import java.io.IOException;

public interface Token {
    Verify verify() throws IOException;
}

public interface Verify {
    Operator build();
}

源码地址: https://github.com/zhangpan-soft/dv-commons

你可能感兴趣的:(java,jwt,dsl,工具,封装)