前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >php+java加密对接算法

php+java加密对接算法

作者头像
joshua317
发布2024-03-09 08:24:35
760
发布2024-03-09 08:24:35
举报
文章被收录于专栏:技术博文技术博文

请求示例:

代码语言:javascript
复制
{
  "appKey": "demo",
  "nonce": "12345",
  "sign": "04a8ba0a19ffc491716131a542729a9c250d84ce4211889a15f920ce974cf23b",
  "signType": "HmacSHA256",
  "timestamp": 1663998514
}

JSON

Copy

Sign生成方式

  1. 拼接参数:signType=?&appKey=?&appSecret=?&nonce=?&timestamp=? 如:signType=HmacSHA256&appKey=demo&appSecret=demo&nonce=12345&timestamp=1663998514。

注意:需要将appSecret设置入签名拼接参数

  1. 字符串转大写 SIGNTYPE=HMACSHA256&APPKEY=DEMO&APPSECRET=DEMO&NONCE=12345&TIMESTAMP=1663998514
  2. 字符串中的字符升序排序前:SIGNTYPE=HMACSHA256&APPKEY=DEMO&APPSECRET=DEMO&NONCE=12345&TIMESTAMP=1663998514
  3. 按字符排序:&&&&111223344555666899=====AAAAACCCDDEEEEEEEEGHHIIKMMMMMNNNOOOPPPPPPRSSSSTTTTYY
  4. HmacMD5或者HmacSHA256加密生成签名,利用秘钥和所需的加密签名算法对上述字符串进行加密成密文,作为sign签名字符串一并发送到请求接口;
  5. 将获取到sign字符串设置进参数即可。

php代码

代码语言:javascript
复制
        $nonce =  rand(100000, 999999);//随机数,可以根据需要自己写函数实现
        $timestamp = time();
        $appKey = 'demo';
        $appSecret = 'demo';
        $params = [
            'appKey' => $appKey,//$appKey,
            'nonce' => $nonce,//$nonce,
            'signType' => 'HmacSHA256',
            'timestamp' => $timestamp,//$timestamp
        ];
        $tempParams = $params;
        $tempParams['appSecret'] = $appSecret;
        $httpBuidParams = http_build_query($tempParams);
        $httpBuidParams = Str::upper($httpBuidParams);

        $charArray = str_split($httpBuidParams);
        // 对字符数组进行排序
        sort($charArray);
        // 将排序后的字符数组转换回字符串
        $data = implode("", $charArray);

        $sign = hash_hmac("sha256", $data, $appSecret);
        echo $sign;

java代码

代码语言:javascript
复制
package com.xxx.utils;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import com.ssc.common.security.annotation.SignIgnore;
import org.apache.commons.codec.digest.HmacUtils;
import org.apache.commons.lang3.StringUtils;

import java.lang.annotation.Annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * 签名入参工具类
 *
 */

public class SignUtils {

    private static final ConcurrentMap<String, String[]> IGNORE_FIELD_CACHE = new ConcurrentHashMap<>();

    /**
     * 签名
     *
     * @param dto           原始参数
     * @param signType      签名算法
     * @param securityKey   加密key
     * @return 签名
     */
    public static String sign(Object dto, String signType, String securityKey) {
        if (Objects.isNull(dto)) {
            return "";
        }

        String[] ignoreFieldArray = getFieldNameByAnn(dto, com.ssc.common.security.annotation.SignIgnore.class);

        HmacUtils util = new HmacUtils(signType, securityKey);
        String sortStr = sortChar(buildPlainText(dto, ignoreFieldArray).toUpperCase());

        return util.hmacHex(sortStr);
    }

    /**
     * 校验签名
     *
     * @param dto           原始参数
     * @param signType      签名算法
     * @param securityKey   加密key
     * @param sign          签名串
     * @return  验证是否通过
     */
    public static boolean baseVerify(Object dto, String signType, String securityKey, String sign) {
        if (Objects.isNull(dto)) {
            return false;
        }

        String[] ignoreFieldArray = getFieldNameByAnn(dto, SignIgnore.class);

        HmacUtils util = new HmacUtils(signType, securityKey);
        String sortStr = sortChar(buildPlainText(dto, ignoreFieldArray).toUpperCase());

        String signVerify = util.hmacHex(sortStr);
        return Objects.equals(signVerify, sign);
    }

    public static Map<String, Object> obj2Map(Object dto, String... ignoreProperties) {
        CopyOptions options = new CopyOptions();
        options.setIgnoreProperties(ignoreProperties);
        return  BeanUtil.beanToMap(dto, new HashMap<>(), options);
    }

    public static String buildPlainText(Object dto, String... ignoreProperties ) {
        if (Objects.isNull(dto)) {
            return "";
        }

        Map<String, Object> map = obj2Map(dto, ignoreProperties);
        StringBuilder sb = new StringBuilder();
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            sb.append(entry.getKey())
            .append("=")
            .append(entry.getValue())
            .append("&");
        }
        return sb.substring(0, sb.length() - 1);
    }

    public static String sortChar(String plainText) {
        if (StringUtils.isBlank(plainText)) {
            return "";
            }

            char[] charArray = plainText.toCharArray();
            Arrays.sort(charArray);

            return new String(charArray);
            }

            private String[] getFieldNameByAnn(Object object, Class<? extends Annotation> ann) {
            assert object != null;
            String[] ignoreFieldList = IGNORE_FIELD_CACHE.get(object.getClass().getName());
            if (Objects.isNull(ignoreFieldList)) {
            List<String> ignoreFields = new ArrayList<>();
            Class<?> entityType = object.getClass();
            while (entityType != null) {
            Field[] declaredFields = entityType.getDeclaredFields();
            for (Field declaredField : declaredFields) {
            if (declaredField.isAnnotationPresent(ann)) {
            ignoreFields.add(declaredField.getName());
            }
            }
            entityType = entityType.getSuperclass();

            }
            ignoreFieldList = ignoreFields.toArray(new String[0]);
            IGNORE_FIELD_CACHE.put(object.getClass().getName(), ignoreFieldList);
            }
            return ignoreFieldList;
            }


            @Target({ElementType.FIELD})
            @Retention(RetentionPolicy.RUNTIME)
            public @interface SignIgnore {

            }
            }
代码语言:javascript
复制
ackage com.xxx.dto;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.xxx.utils.SignUtils.SignIgnore;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.io.Serializable;

/**
 * 签名DTO
 *
 */

@Data
public class BaseSignDTO implements Serializable {

    @SignIgnore
    @ApiModelProperty(value = "签名", required = true, example = "abcdefg")
    private String sign;

    @ApiModelProperty(value = "时间戳", required = true, example = "1663998514")
    private Long timestamp;

    @ApiModelProperty(value = "签名方式", required = true, example = "HmacSHA256")
    private String signType;

    @ApiModelProperty(value = "随机数", required = true, example = "12345")
    private String nonce;

    @ApiModelProperty(value = "应用Key", required = true)
    private String appKey;

    @ApiModelProperty(value = "应用密匙", hidden = true)
    private String appSecret;
}

本文为joshua317原创文章,转载请注明:转载自joshua317博客 https://www.joshua317.com/article/322

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2024-03-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档