hutool jwt token 工具类

自定义基于 jwt token的二次摘要签名认证

一:依赖

<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.8.0</version>
</dependency>

二:jwt认证结果

package com.auth;

import java.util.Map;

/**
 * @author Administrator
 */
public class JwtVerifyResult{
	/** 1 是否成功 **/
	private Boolean success;
	/** 2 返回消息 **/
	private String msg;
	/** 3 jwt负载 **/
	private Map<String,String> payload;

	public JwtVerifyResult() {
	}

	public JwtVerifyResult(Boolean success, String msg) {
		this.success = success;
		this.msg = msg;
	}

	public Boolean getSuccess() {
		return success;
	}

	public void setSuccess(Boolean success) {
		this.success = success;
	}

	public String getMsg() {
		return msg;
	}

	public void setMsg(String msg) {
		this.msg = msg;
	}

	public Map<String, String> getPayload() {
		return payload;
	}

	public void setPayload(Map<String, String> payload) {
		this.payload = payload;
	}

	@Override
	public String toString() {
		return "JwtResult{" +
				"success=" + success +
				", msg='" + msg + '\'' +
				", payload=" + payload +
				'}';
	}
}

三:认证工具类

package com.sdhttp.util.auth;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.exceptions.ValidateException;
import cn.hutool.core.lang.TypeReference;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTPayload;
import cn.hutool.jwt.RegisteredPayload;
import cn.hutool.jwt.signers.JWTSigner;
import cn.hutool.jwt.signers.JWTSignerUtil;

import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author Administrator
 */
@Component
public class UtilJwt {

	/**
	 * jwt 签名秘钥,可以更换其他不常用的自定义签名器: JWTSignerUtil
	 */
	static final JWTSigner jwtSigner = JWTSignerUtil.hs256("!34ADASfhsrujwstrfhwdg@#$$@#efh3".getBytes());
	/**
	 * 自定义二重认证 token key
	 */
	static final String AUTHTOKEN_KEY = "at";

	public static void main(String[] args) {

		Map<String,String> payload = new HashMap<>();
		payload.put("uuid","345345");
		payload.put("ts",DateUtil.current()+"");

		String testAppkey = "testAppkey";
		String testAppsecret = "*************************";
		String token = createToken(payload,testAppkey,testAppsecret);
		System.out.println(token);

		JwtVerifyResult jwtVerifyResult = validateToken(token,testAppkey,testAppsecret);
		if(jwtVerifyResult.getSuccess()){
			payload = jwtVerifyResult.getPayload();
			System.out.println("负载:"+payload.toString());
		}else{
			System.out.println("验证失败:"+jwtVerifyResult.toString());
		}
	}

	/**
     * 生成安全的 jwt token
     * 理论上:内部系统交互:每隔3个月,更新 appkey,appsecret
     * 外部系统交互:不用更新 appkey,appsecret,但必须要求其验证负载 ts 和 at(authToken)
     * <p>
     * 时间校验具有多种方法:生效时间、失效时间、签发时间
     * 此处只用失效时间校验:https://www.hutool.cn/docs/#/jwt/JWT验证-JWTValidator
     * <p>
     * 负载签名时间:iat(签发时间-强制)、exp(过期时间校验-强制)、at(内嵌再次token校验),已被占用
     * 可能使用的高级占用参数:详见 hutool 的RegisteredPayload 接口
     *
     * @param payload   jwt负载
     * @param appkey    签名key
     * @param appsecret 签名秘钥
     * @return
     */
    public static String createToken(Map<String, String> payload, String appkey, String appsecret) {

        Date dateNow = new Date();
        //1.构建自定义的签名摘要(安全2)
        System.out.println(dateNow.getTime());
        String authToken = SecureUtil.md5(SecureUtil.sha256(appkey + "_" + DateUtil.formatDateTime(dateNow) + "_" + appsecret));
        payload.put(AUTHTOKEN_KEY, authToken);

        //3.创建 jwt 签名,存放参数;2.签名时间 3。设置过期时间为当天结束(validateToken方法:容忍校验2分钟),4.hash256签名为(安全4)
        return JWT.create()
                .addPayloads(payload)
                .setIssuedAt(dateNow)
                .setExpiresAt(DateUtil.endOfDay(dateNow))
                .sign(jwtSigner);
    }

    /**
     * jwt 验证,1)hash256签名,2)失效时间,3)自定义二重安全校验
     *
     * @param token     生成的jwt token
     * @param appkey    签名key
     * @param appsecret 签名秘钥
     * @return map :当error = "ok",会额外多出 payload
     */
    public static JwtVerifyResult validateToken(String token, String appkey, String appsecret) {

        try {
            JWT jwt = JWT.of(token);
            jwt.setSigner(jwtSigner);

            //1.验证hash256签名
            Boolean hs256Bool = jwt.verify();
            if (!hs256Bool) {
                return new JwtVerifyResult(false, "hash256签名校验失败");
            }

            //2.验证签名的时间,容忍度为2分钟
            Boolean validateBool = jwt.validate(120L);
            if (!validateBool) {
                return new JwtVerifyResult(false, "时间负载校验失败");
            }

            //3.获取二重 authToken 认证校验
            JWTPayload jwtPayload = jwt.getPayload();
            Date subAtDate = jwtPayload.getClaimsJson().getDate(RegisteredPayload.ISSUED_AT);

            String atScource = String.valueOf(jwtPayload.getClaim(AUTHTOKEN_KEY));
            String authToken = SecureUtil.md5(SecureUtil.sha256(appkey + "_" +DateUtil.formatDateTime(subAtDate) + "_" + appsecret));

            if (StrUtil.isEmpty(atScource) || !atScource.equals(authToken)) {
                return new JwtVerifyResult(false, "二重身份认证校验失败");
            }

            //4.将负载参数转换成map返回
            JSONObject payloadJson = jwtPayload.getClaimsJson();
            payloadJson.remove(AUTHTOKEN_KEY);
            JwtVerifyResult jwtVerifyResult = new JwtVerifyResult(true, "签名有效");
            jwtVerifyResult.setPayload(JSONUtil.toBean(payloadJson, new TypeReference<Map<String, String>>() {
            }, true));
            return jwtVerifyResult;

        } catch (ValidateException e) {
            return new JwtVerifyResult(true, "无效的签名");
        }
    }
}

猜你喜欢

转载自blog.csdn.net/qq_26408545/article/details/124771686