简单验签生成工具类

最近对接多个快递公司,由于需要引入多个官方sdk,抽取了一个统一工具类

枚举

package com.joyi.courier.common.enums;

import lombok.Getter;

/**
 * 编码枚举
 *
 * @author Wangnz
 */

@Getter
public enum CodecType {
    /**
     * 编码枚举
     */
    MD5("MD5"),
    URL("URL"),
    BASE64("base64");


    /**
     * 描述
     */
    private final String desc;


    CodecType(String desc) {
        this.desc = desc;
    }
}

工具类

package com.joyi.courier.util;

import cn.hutool.core.util.ObjectUtil;
import com.joyi.courier.common.enums.CodecType;

import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.function.Consumer;

/**
 * 编码工具类
 * 未实现的加密方式 自己添加对应方法即可
 *
 * @author Wangnz
 */
public class CodecUtils {

    private static final Map<CodecType, Consumer<byte[]>> CODEC_METHOD_MAP = new HashMap<>();
    private static final ThreadLocal<byte[]> SIGN_THREAD_LOCAL = new ThreadLocal<>();

    static {
        CODEC_METHOD_MAP.put(CodecType.MD5, CodecUtils::md5);
        CODEC_METHOD_MAP.put(CodecType.URL, CodecUtils::urlEncode);
        CODEC_METHOD_MAP.put(CodecType.BASE64, CodecUtils::base64Encode);
    }

    /**
     * 签名制作
     *
     * @param str        加密字符串
     * @param codecTypes 加密顺序
     * @return
     */
    public static String signCreate(String str, CodecType... codecTypes) {
        if (codecTypes == null || codecTypes.length == 0) {
            return str;
        }
        try {
            SIGN_THREAD_LOCAL.set(getBytesUtf8(str));
            for (CodecType codecType : codecTypes) {
                Consumer<byte[]> run = CODEC_METHOD_MAP.get(codecType);
                if (run == null) {
                    throw new RuntimeException("codecType error");
                }
                run.accept(SIGN_THREAD_LOCAL.get());
            }
            //如果最后一步为MD5 则转换为16进制
            if (CodecType.MD5.equals(codecTypes[codecTypes.length - 1])) {
                return bytesToHex(SIGN_THREAD_LOCAL.get());
            } else {
                return newStringUtf8(SIGN_THREAD_LOCAL.get());
            }
        } catch (RuntimeException e) {
            return null;
        } finally {
            SIGN_THREAD_LOCAL.remove();
        }
    }

    /**
     * 验签工具
     *
     * @param reqAndSecretStr 快递公司请求加密前的字符串(一般为 请求bodyJson 拼接 Secret)
     * @param reqSign         快递公司请求签名
     * @param codecTypes      加密方式顺序
     * @return
     */
    public static boolean checkSign(String reqAndSecretStr, String reqSign, CodecType... codecTypes) {
        if (!ObjectUtil.isAllNotEmpty(reqAndSecretStr, reqSign) || codecTypes.length == 0) {
            return false;
        }
        String real = signCreate(reqAndSecretStr, codecTypes);
        return reqSign.equals(real);
    }


    /**
     * md5
     *
     * @param str
     */
    public static void md5(byte[] str) {
        MessageDigest md5 = null;
        try {
            md5 = MessageDigest.getInstance("MD5");
            md5.update(str);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("md5 error");
        }
        SIGN_THREAD_LOCAL.set(md5.digest());
    }

    /**
     * urlEncode
     *
     * @param str
     */
    public static void urlEncode(byte[] str) {
        SIGN_THREAD_LOCAL.set(getBytesUtf8(URLEncoder.encode(newStringUtf8(str), StandardCharsets.UTF_8)));
    }

    /**
     * base64
     *
     * @param str
     */
    public static void base64Encode(byte[] str) {
        SIGN_THREAD_LOCAL.set(Base64.getEncoder().encode(str));
    }


    /**
     * 将字节数组转换为十六进制字符串
     *
     * @param bytes byte
     * @return str
     */
    private static String bytesToHex(byte[] bytes) {
        StringBuilder result = new StringBuilder();
        for (byte b : bytes) {
            result.append(String.format("%02x", b));
        }
        return result.toString();
    }

    public static String newStringUtf8(byte[] str) {
        return new String(str, StandardCharsets.UTF_8);
    }

    public static byte[] getBytesUtf8(String str) {
        return str.getBytes(StandardCharsets.UTF_8);
    }

    public static String UUID() {
        return UUID.randomUUID().toString().replaceAll("-", "");
    }

    /**
     * 拼接字符串 逗号分隔
     * 接收其他类型的自己重载
     *
     * @param list
     * @return
     */
    public static String appendComma(List<String> list) {
        StringJoiner joiner = new StringJoiner(",");
        list.forEach(joiner::add);
        return joiner.toString();
    }

    public static void main(String[] args) {
        //顺丰
        System.out.println(signCreate("111", CodecType.URL, CodecType.MD5, CodecType.BASE64));
        //极兔
        System.out.println(signCreate("111", CodecType.MD5, CodecType.BASE64));
        //韵达
        System.out.println(signCreate("111", CodecType.MD5));
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值