JWT需要集成第三方框架?不,自己手写一个

本文详细介绍JWT(JSON Web Token)的生成与校验过程,包括使用SHA256算法创建自定义Token小工具,以及如何通过算法接口定义和实现加密逻辑。同时,提供了JWSBuilder类用于构建JWT,并演示了生成与解析Token的具体步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

温故而知新,可以为师矣。

从前面的博客JWT就是这么简单知道了JWT的生成规则是使用BASE64编码。

所以朕水今天就带大家来写一个简单的生成Token的小工具,让大家更能方便理解JWT。

token加密算法

朕水只示范SHA256的实现,需要更多扩展则需要小伙伴们的动手能力了嗷

写一个算法的接口,接口定义算法类型和签名

//算法接口
public interface Algorithm {
    //算法类型
    String alg();
	//算法返回的签名
    String algorithm(String message);
}

朕水写一个SHA256的算法实现

public class HMAC256Algorithm implements Algorithm {
	//算法类型
    private static final String ALG ="HS256";
	//密钥
    private final String secret;
	
    public HMAC256Algorithm(String secret){
        //构造时传入密钥
        if(secret==null||"".equals(secret)){
            throw new RuntimeException("must has secret");
        }
        this.secret = secret;
    }

    @Override
    public String algorithm(String message) {
        String hash = "";
        try {
            //使用对应的算法加密
            Mac mac = Mac.getInstance("HmacSHA256");
            mac.init(new SecretKeySpec(secret.getBytes(), "HmacSHA256"));
            //将 加密的 二进制结果进行Base64-URL编码
            //Base64-URL编码规则:  +变为-  /变为_  去掉等号=
            hash = Base64.encodeBase64URLSafeString(mac.doFinal(message.getBytes()));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return hash;
    }
    @Override
    public String alg() {
    //返回算法类型
        return ALG;
    }
}

在URL中字符+和/是不能在url中做为参数的,所以base64有一种urlSafe编码。在JWT官网上有对应的说明是使用BaseUrl进行编码。

token生成逻辑
public class JWSBuilder {

    private Algorithm algorithm;

    private Map<String,String> header = new HashMap<>();

    private Map<String,Object> payloadMap = new HashMap<>();

    private String payloadBody;

    public JWSBuilder(Algorithm algorithm) {
        this.algorithm = algorithm;
    }

    public JWSBuilder header(Map<String,String> header) {
        this.header = header;
        return this;
    }
    public JWSBuilder sub(String sub) {
        payloadMap.put("sub",sub);
        return this;
    }
    public JWSBuilder iat(Date iat) {
        payloadMap.put("iat",iat.getTime());
        return this;
    }

    public JWSBuilder claim(String key,String value){
        payloadMap.put(key,value);
        return this;
    }

    public JWSBuilder payloadBody(String payloadBody){
        this.payloadBody = payloadBody;
        return this;
    }

    public String build() {
        if(payloadMap.isEmpty()&&(payloadBody==null||"".equals(payloadBody.trim()))){
            throw new RuntimeException("not has payload message");
        }
        //将载荷拼接为JSON
        header.put("alg",algorithm.alg());
        StringBuilder headerSb = new StringBuilder("{");
        header.forEach((key,val)->{
            headerSb.append("\"");
            headerSb.append(key);
            headerSb.append("\":");
            headerSb.append("\"");
            headerSb.append(val);
            headerSb.append("\"");
            headerSb.append(",");
        });
        headerSb.replace(headerSb.length()-1,headerSb.length(),"}");
        //如果为空或者有载荷实体payloadBody则不拼接JSON
        if(payloadBody==null){
            StringBuilder payloadSb = new StringBuilder("{");
            payloadMap.forEach((key,val)->{
                payloadSb.append("\"");
                payloadSb.append(key);
                payloadSb.append("\":");
                payloadSb.append("\"");
                payloadSb.append(val);
                payloadSb.append("\"");
                payloadSb.append(",");
            });
            payloadSb.replace(payloadSb.length()-1,payloadSb.length(),"}");
            payloadBody=payloadSb.toString();
        }
        String header = Base64.encodeBase64URLSafeString(headerSb.toString().getBytes());
        String payload = Base64.encodeBase64URLSafeString(payloadBody.getBytes());
        String sign = this.algorithm.algorithm(header + "." + payload);
        return header+"."+payload+"."+sign;
    }
}

上面的代码朕水只写了sub、iat的简单封装,需要扩展的小伙伴需要自己写对应的代码。生成token的Builder类就写好了,朕水去测试一下。

测试生成token
Algorithm hmac256Algorithm = new HMAC256Algorithm("zhenshui");
String token = new JWSBuilder(hmac256Algorithm)
    .sub("demo")
    .claim("auth","zhenshui")
    .build();
System.out.println(token);

token生成成功!

将token拿去官网debugger一下试试是否正确。朕水测试是正确的。

校验token

接下来朕水写一个校验类,对token进行校验。和上面一样,朕水只写一个简单的校验,需要更复杂的逻辑则需要小伙伴自己手动diy了

public class JWSParser {

    private Algorithm algorithm;

    private String token;

    private String header;

    private String payloadBody;

    private Map<String,String> verifyMap;

    public JWSParser(Algorithm algorithm) {
        this.algorithm = algorithm;
    }

    public JWSParser sub(String sub){
        verifyMap.put("sub",sub);
        return this;
    }

    public String getHeader() {
        return header;
    }

    public String getPayloadBody() {
        return payloadBody;
    }

    public JWSParser parser(String token){
        //截取前面两节
        String perHeaderAndPayloadToken = token.substring(0, token.lastIndexOf("."));
        //重新加密
        String algorithm = this.algorithm.algorithm(perHeaderAndPayloadToken);
        //截取后面一节进行比较
        String signStr = token.substring(token.lastIndexOf(".")+1);
        if (!signStr.equals(algorithm)) {
            //签名不一致
            throw new RuntimeException("token exception");
        }
        //得到载体、转化
        String payload = perHeaderAndPayloadToken.substring( perHeaderAndPayloadToken.indexOf(".")+1);
        payloadBody = new String(Base64.decodeBase64URLSafe(payload));
        //校验字段:过期时间、主体、签发人等等信息
        //TODO
        //得到头部、转化
        String headerBase64Str = perHeaderAndPayloadToken.substring(0, perHeaderAndPayloadToken.indexOf("."));
        this.header  = new String(Base64.decodeBase64URLSafe(headerBase64Str));
        return this;
    }
}

上面的校验类写完了,但是校验并没有写完整,只是简单的做了签名的校验。如果不依赖第三方库转化JSON比较复杂,所以朕水就没有写。

校验token测试

写完了之后,朕水去校验一下token

解析成功,好啦。相信小伙伴们看完这篇后对常用的JWS的生成和解密已经很熟悉了。

tips: 如果是非对称加密则需要对应的加密和解密方法。

目前的JWT框架都比较完善且有专人进行维护,小伙伴不要在实际项目中使用自己写的Token生成。

如果不知道使用哪一个JWT框架,可以看看朕水的文章JWT框架简单测评,哪款是你的菜

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值