【Java】阿里云RPC调用签名计算方式

官方文档

https://help.aliyun.com/document_detail/315526.html?spm=a2c4g.2391591.0.0.36e427b5X3ls6H#sectiondiv-6jf-89b-wfa

依赖

import cn.hutool.http.HttpRequest;
import com.alibaba.fastjson.JSON;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

调用方式

以下为短信发送调用方式,其他接口调用方式类似

private String endPoint = "dysmsapi.aliyuncs.com";
private String ACCESS_KEY_ID;
private String ACCESS_SECRET;
private String SIGN_NAME;
private String ACTION;

private String sendSmsFromAliYun(String templateCode, HashMap<String, String> templateParamMap, String phoneNumbers) {
    //获取timestamp(UTC时间)
    ZonedDateTime currentTime = ZonedDateTime.now(ZoneOffset.UTC);
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'");
    String formattedTime = currentTime.format(formatter);

    //模板内字段转为json
    String templateParam = JSON.toJSONString(templateParamMap);

    //获取随机数
    String random = String.valueOf(Math.random());

    //包装请求参数
    HashMap<String, String> params = new HashMap<>();
    //公共参数
    params.put("AccessKeyId", ACCESS_KEY_ID);
    params.put("Action", ACTION);
    params.put("Format", "JSON");
    params.put("RegionId", "cn-beijing");
    params.put("SignatureMethod", "HMAC-SHA1");
    params.put("SignatureNonce", random);
    params.put("SignatureVersion", "1.0");
    params.put("Timestamp", formattedTime);
    params.put("Version", "2017-05-25");
    //接口参数
    params.put("PhoneNumbers", phoneNumbers);
    params.put("SignName", SIGN_NAME);
    params.put("TemplateCode", templateCode);
    params.put("TemplateParam", templateParam);

    //生成阿里云签名
    String canonicalizedQueryString = encodeURIComponent(sortParam(params));
    //此接口采用POST方式,需要GET方法可自行更改(下方httpRequest也需要换成get方法)
    String signature = generateSignature("POST", canonicalizedQueryString, ACCESS_SECRET);
    //合成请求url
    String finalUrl = generateFinalUrl(canonicalizedQueryString, signature);
    //post
    String result = HttpRequest.post(finalUrl).execute().body();

    return result;
}

签名计算方法

//按字典序对参数排序
private HashMap<String, String> sortParam(HashMap<String, String> params) {
    // 将HashMap的entrySet转换为List
    List<Map.Entry<String, String>> entryList = new ArrayList<>(params.entrySet());

    // 使用Collections.sort对List进行排序,传入自定义的Comparator
    Collections.sort(entryList, new Comparator<Map.Entry<String, String>>() {
        @Override
        public int compare(Map.Entry<String, String> o1, Map.Entry<String, String> o2) {
            return o1.getKey().compareTo(o2.getKey());
        }
    });

    // 创建一个新的有序HashMap
    HashMap<String, String> sortedParams = new LinkedHashMap<>();

    // 将排序后的entry逐个放入sortedParams
    for (Map.Entry<String, String> entry : entryList) {
        sortedParams.put(entry.getKey(), entry.getValue());
    }

    // 返回排序后的HashMap
    return sortedParams;
}

//按照RFC3986规则编码对请求参数和参数值进行编码
private String encodeURIComponent(HashMap<String, String> params) {
    StringBuilder sb = new StringBuilder();

    try {
        // 遍历参数并进行编码
        for (Map.Entry<String, String> entry : params.entrySet()) {
            String encodedKey = encode(entry.getKey());
            String encodedValue = encode(entry.getValue());

            // 将编码后的参数和参数值用等号连接,并用与号连接多个参数
            sb.append(encodedKey).append("=").append(encodedValue).append("&");
        }

        // 删除最后一个多余的与号
        sb.delete(sb.length() - 1, sb.length());
    } catch (Exception e) {
        e.printStackTrace();
    }

    // 返回编码后的请求参数
    return sb.toString();
}

//使用HMAC-SHA1算法计算签名
private String generateSignature(String httpMethod, String canonicalizedQueryString, String accessSecret) {
    try {
        //'/'URL编码后为%2F
        String stringToSign = httpMethod + "&%2F&" + encode(canonicalizedQueryString);
        accessSecret = accessSecret + "&";

        // 将AccessSecret转换为UTF-8编码的字节数组
        byte[] secretBytes = accessSecret.getBytes(StandardCharsets.UTF_8);

        // 创建HMAC-SHA1算法实例,并使用AccessSecret初始化
        Mac mac = Mac.getInstance("HmacSHA1");
        SecretKeySpec secretKeySpec = new SecretKeySpec(secretBytes, "HmacSHA1");
        mac.init(secretKeySpec);

        // 计算待签名字符串的字节数组
        byte[] stringToSignBytes = stringToSign.getBytes(StandardCharsets.UTF_8);

        // 计算签名
        byte[] signatureBytes = mac.doFinal(stringToSignBytes);

        // 对签名进行Base64编码
        String signature = Base64.getEncoder().encodeToString(signatureBytes);

        return signature;
    } catch (Exception e) {
        return null;
    }
}

//将生成的签名拼接至URL结尾
private String generateFinalUrl(String canonicalizedQueryString, String signature) {
    return "http://" + endPoint + "/?" + canonicalizedQueryString + "&Signature=" + encode(signature);
}

//url编码 空格的编码为"%20"而不是"+"
private String encode(String s) {
    try {
        return URLEncoder.encode(s, StandardCharsets.UTF_8.toString()).replaceAll("\\+", "%20");
    } catch (Exception e) {
        return null;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值