Commit 0c8163c4092de70c9fb00e50754f85e04b7b18ff

Authored by scholar
1 parent 66bbbc95

优化华为短信客户端实现,去除两个新增类HuaweiRequest、HuaweiSigner

yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/client/impl/HuaweiSmsClient.java
@@ -2,16 +2,17 @@ package cn.iocoder.yudao.module.system.framework.sms.core.client.impl; @@ -2,16 +2,17 @@ package cn.iocoder.yudao.module.system.framework.sms.core.client.impl;
2 2
3 3
4 import cn.hutool.core.lang.Assert; 4 import cn.hutool.core.lang.Assert;
  5 +import cn.hutool.core.util.HexUtil;
5 import cn.hutool.core.util.StrUtil; 6 import cn.hutool.core.util.StrUtil;
6 7
  8 +import cn.hutool.crypto.SecureUtil;
  9 +import cn.hutool.crypto.digest.DigestUtil;
7 import cn.hutool.json.JSONArray; 10 import cn.hutool.json.JSONArray;
8 import cn.iocoder.yudao.framework.common.core.KeyValue; 11 import cn.iocoder.yudao.framework.common.core.KeyValue;
9 import cn.iocoder.yudao.framework.common.util.json.JsonUtils; 12 import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
10 import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsReceiveRespDTO; 13 import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsReceiveRespDTO;
11 import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsSendRespDTO; 14 import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsSendRespDTO;
12 import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsTemplateRespDTO; 15 import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsTemplateRespDTO;
13 -import cn.iocoder.yudao.module.system.framework.sms.core.client.utils.HuaweiRequest;  
14 -import cn.iocoder.yudao.module.system.framework.sms.core.client.utils.HuaweiSigner;  
15 import cn.iocoder.yudao.module.system.framework.sms.core.enums.SmsTemplateAuditStatusEnum; 16 import cn.iocoder.yudao.module.system.framework.sms.core.enums.SmsTemplateAuditStatusEnum;
16 import cn.iocoder.yudao.module.system.framework.sms.core.property.SmsChannelProperties; 17 import cn.iocoder.yudao.module.system.framework.sms.core.property.SmsChannelProperties;
17 import org.apache.http.client.methods.*; 18 import org.apache.http.client.methods.*;
@@ -30,6 +31,7 @@ import org.apache.http.HttpResponse; @@ -30,6 +31,7 @@ import org.apache.http.HttpResponse;
30 import java.io.UnsupportedEncodingException; 31 import java.io.UnsupportedEncodingException;
31 import java.net.URLEncoder; 32 import java.net.URLEncoder;
32 import java.nio.charset.StandardCharsets; 33 import java.nio.charset.StandardCharsets;
  34 +import java.text.SimpleDateFormat;
33 import java.util.*; 35 import java.util.*;
34 36
35 37
@@ -55,6 +57,7 @@ public class HuaweiSmsClient extends AbstractSmsClient { @@ -55,6 +57,7 @@ public class HuaweiSmsClient extends AbstractSmsClient {
55 */ 57 */
56 public static final String API_CODE_SUCCESS = "OK"; 58 public static final String API_CODE_SUCCESS = "OK";
57 private static final Logger LOGGER = LoggerFactory.getLogger(HuaweiSmsClient.class); 59 private static final Logger LOGGER = LoggerFactory.getLogger(HuaweiSmsClient.class);
  60 +
58 public HuaweiSmsClient(SmsChannelProperties properties) { 61 public HuaweiSmsClient(SmsChannelProperties properties) {
59 super(properties); 62 super(properties);
60 Assert.notEmpty(properties.getApiKey(), "apiKey 不能为空"); 63 Assert.notEmpty(properties.getApiKey(), "apiKey 不能为空");
@@ -79,6 +82,18 @@ public class HuaweiSmsClient extends AbstractSmsClient { @@ -79,6 +82,18 @@ public class HuaweiSmsClient extends AbstractSmsClient {
79 //选填,短信状态报告接收地址,推荐使用域名,为空或者不填表示不接收状态报告 82 //选填,短信状态报告接收地址,推荐使用域名,为空或者不填表示不接收状态报告
80 String statusCallBack = properties.getCallbackUrl(); 83 String statusCallBack = properties.getCallbackUrl();
81 84
  85 + SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'", Locale.ENGLISH);
  86 + sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
  87 + String singerDate = sdf.format(new Date());
  88 +
  89 + // ************* 步骤 1:拼接规范请求串 *************
  90 + String httpRequestMethod = "POST";
  91 + String canonicalUri = "/sms/batchSendSms/v1/";
  92 + String canonicalQueryString = "";//查询参数为空
  93 + String canonicalHeaders = "content-type:application/x-www-form-urlencoded\n"
  94 + + "host:smsapi.cn-north-4.myhuaweicloud.com:443\n"
  95 + + "x-sdk-date:" + singerDate + "\n";
  96 + String signedHeaders = "content-type;host;x-sdk-date";
82 /** 97 /**
83 * 选填,使用无变量模板时请赋空值 String templateParas = ""; 98 * 选填,使用无变量模板时请赋空值 String templateParas = "";
84 * 单变量模板示例:模板内容为"您的验证码是${NUM_6}"时,templateParas可填写为"[\"111111\"]" 99 * 单变量模板示例:模板内容为"您的验证码是${NUM_6}"时,templateParas可填写为"[\"111111\"]"
@@ -92,31 +107,34 @@ public class HuaweiSmsClient extends AbstractSmsClient { @@ -92,31 +107,34 @@ public class HuaweiSmsClient extends AbstractSmsClient {
92 //请求Body,不携带签名名称时,signature请填null 107 //请求Body,不携带签名名称时,signature请填null
93 String body = buildRequestBody(sender, receiver, templateId, templateParas, statusCallBack, null); 108 String body = buildRequestBody(sender, receiver, templateId, templateParas, statusCallBack, null);
94 if (null == body || body.isEmpty()) { 109 if (null == body || body.isEmpty()) {
95 - LOGGER.warn("body is null.");  
96 return null; 110 return null;
97 } 111 }
  112 + String hashedRequestBody = HexUtil.encodeHexStr(DigestUtil.sha256(body));
  113 + String canonicalRequest = httpRequestMethod + "\n" + canonicalUri + "\n" + canonicalQueryString + "\n"
  114 + + canonicalHeaders + "\n" + signedHeaders + "\n" + hashedRequestBody;
  115 +
  116 + // ************* 步骤 2:拼接待签名字符串 *************
  117 + String hashedCanonicalRequest = HexUtil.encodeHexStr(DigestUtil.sha256(canonicalRequest));
  118 + String stringToSign = "SDK-HMAC-SHA256" + "\n" + singerDate + "\n" + hashedCanonicalRequest;
  119 +
  120 + // ************* 步骤 3:计算签名 *************
  121 + String signature = SecureUtil.hmacSha256(properties.getApiSecret()).digestHex(stringToSign);
98 122
99 - HuaweiRequest request = new HuaweiRequest();  
100 - request.setKey(properties.getApiKey());  
101 - request.setSecret(properties.getApiSecret());  
102 - request.setMethod("POST");  
103 - request.setUrl(url);  
104 - request.addHeader("Content-Type", "application/x-www-form-urlencoded");  
105 - request.setBody(body);  
106 - LOGGER.info("Print the body: {}", body);  
107 -  
108 - HuaweiSigner signer = new HuaweiSigner("SDK-HMAC-SHA256");  
109 - signer.sign(request); 123 + // ************* 步骤 4:拼接 Authorization *************
  124 + String authorization = "SDK-HMAC-SHA256" + " " + "Access=" + properties.getApiKey() + ", "
  125 + + "SignedHeaders=" + signedHeaders + ", " + "Signature=" + signature;
  126 +
  127 + // ************* 步骤 5:构造HttpRequest 并执行request请求,获得response *************
110 HttpUriRequest postMethod = RequestBuilder.post() 128 HttpUriRequest postMethod = RequestBuilder.post()
111 .setUri(url) 129 .setUri(url)
112 - .setEntity(new StringEntity(request.getBody(), StandardCharsets.UTF_8)) 130 + .setEntity(new StringEntity(body, StandardCharsets.UTF_8))
113 .setHeader("Content-Type","application/x-www-form-urlencoded") 131 .setHeader("Content-Type","application/x-www-form-urlencoded")
114 - .setHeader("X-Sdk-Date",request.getHeaders().get("X-Sdk-Date"))  
115 - .setHeader("Authorization",request.getHeaders().get("Authorization")) 132 + .setHeader("X-Sdk-Date",singerDate)
  133 + .setHeader("Authorization",authorization)
116 .build(); 134 .build();
117 CloseableHttpClient client = HttpClientBuilder.create().build(); 135 CloseableHttpClient client = HttpClientBuilder.create().build();
118 -  
119 HttpResponse response = client.execute(postMethod); 136 HttpResponse response = client.execute(postMethod);
  137 +
120 return new SmsSendRespDTO().setSuccess(Objects.equals(response.getStatusLine().getReasonPhrase(), API_CODE_SUCCESS)).setSerialNo(Integer.toString(response.getStatusLine().getStatusCode())) 138 return new SmsSendRespDTO().setSuccess(Objects.equals(response.getStatusLine().getReasonPhrase(), API_CODE_SUCCESS)).setSerialNo(Integer.toString(response.getStatusLine().getStatusCode()))
121 .setApiRequestId(null).setApiCode(null).setApiMsg(null); 139 .setApiRequestId(null).setApiCode(null).setApiMsg(null);
122 } 140 }
@@ -141,7 +159,6 @@ public class HuaweiSmsClient extends AbstractSmsClient { @@ -141,7 +159,6 @@ public class HuaweiSmsClient extends AbstractSmsClient {
141 159
142 private static void appendToBody(StringBuilder body, String key, String val) throws UnsupportedEncodingException { 160 private static void appendToBody(StringBuilder body, String key, String val) throws UnsupportedEncodingException {
143 if (null != val && !val.isEmpty()) { 161 if (null != val && !val.isEmpty()) {
144 - LOGGER.info("Print appendToBody: {}:{}", key, val);  
145 body.append(key).append(URLEncoder.encode(val, "UTF-8")); 162 body.append(key).append(URLEncoder.encode(val, "UTF-8"));
146 } 163 }
147 } 164 }
@@ -181,20 +198,17 @@ public class HuaweiSmsClient extends AbstractSmsClient { @@ -181,20 +198,17 @@ public class HuaweiSmsClient extends AbstractSmsClient {
181 /** 198 /**
182 * 短信资源的更新时间,通常为短信平台接收短信状态报告的时间 199 * 短信资源的更新时间,通常为短信平台接收短信状态报告的时间
183 */ 200 */
184 - @JsonProperty("updateTime")  
185 @JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT) 201 @JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT)
186 private LocalDateTime updateTime; 202 private LocalDateTime updateTime;
187 203
188 /** 204 /**
189 * 短信状态报告枚举值 205 * 短信状态报告枚举值
190 */ 206 */
191 - @JsonProperty("status")  
192 private String status; 207 private String status;
193 208
194 /** 209 /**
195 * 发送短信成功时返回的短信唯一标识。 210 * 发送短信成功时返回的短信唯一标识。
196 */ 211 */
197 - @JsonProperty("smsMsgId")  
198 private String smsMsgId; 212 private String smsMsgId;
199 } 213 }
200 214