Commit 0c8163c4092de70c9fb00e50754f85e04b7b18ff
1 parent
66bbbc95
优化华为短信客户端实现,去除两个新增类HuaweiRequest、HuaweiSigner
Showing
1 changed file
with
36 additions
and
22 deletions
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 | 2 | |
| 3 | 3 | |
| 4 | 4 | import cn.hutool.core.lang.Assert; |
| 5 | +import cn.hutool.core.util.HexUtil; | |
| 5 | 6 | import cn.hutool.core.util.StrUtil; |
| 6 | 7 | |
| 8 | +import cn.hutool.crypto.SecureUtil; | |
| 9 | +import cn.hutool.crypto.digest.DigestUtil; | |
| 7 | 10 | import cn.hutool.json.JSONArray; |
| 8 | 11 | import cn.iocoder.yudao.framework.common.core.KeyValue; |
| 9 | 12 | import cn.iocoder.yudao.framework.common.util.json.JsonUtils; |
| 10 | 13 | import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsReceiveRespDTO; |
| 11 | 14 | import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsSendRespDTO; |
| 12 | 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 | 16 | import cn.iocoder.yudao.module.system.framework.sms.core.enums.SmsTemplateAuditStatusEnum; |
| 16 | 17 | import cn.iocoder.yudao.module.system.framework.sms.core.property.SmsChannelProperties; |
| 17 | 18 | import org.apache.http.client.methods.*; |
| ... | ... | @@ -30,6 +31,7 @@ import org.apache.http.HttpResponse; |
| 30 | 31 | import java.io.UnsupportedEncodingException; |
| 31 | 32 | import java.net.URLEncoder; |
| 32 | 33 | import java.nio.charset.StandardCharsets; |
| 34 | +import java.text.SimpleDateFormat; | |
| 33 | 35 | import java.util.*; |
| 34 | 36 | |
| 35 | 37 | |
| ... | ... | @@ -55,6 +57,7 @@ public class HuaweiSmsClient extends AbstractSmsClient { |
| 55 | 57 | */ |
| 56 | 58 | public static final String API_CODE_SUCCESS = "OK"; |
| 57 | 59 | private static final Logger LOGGER = LoggerFactory.getLogger(HuaweiSmsClient.class); |
| 60 | + | |
| 58 | 61 | public HuaweiSmsClient(SmsChannelProperties properties) { |
| 59 | 62 | super(properties); |
| 60 | 63 | Assert.notEmpty(properties.getApiKey(), "apiKey 不能为空"); |
| ... | ... | @@ -79,6 +82,18 @@ public class HuaweiSmsClient extends AbstractSmsClient { |
| 79 | 82 | //选填,短信状态报告接收地址,推荐使用域名,为空或者不填表示不接收状态报告 |
| 80 | 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 | 98 | * 选填,使用无变量模板时请赋空值 String templateParas = ""; |
| 84 | 99 | * 单变量模板示例:模板内容为"您的验证码是${NUM_6}"时,templateParas可填写为"[\"111111\"]" |
| ... | ... | @@ -92,31 +107,34 @@ public class HuaweiSmsClient extends AbstractSmsClient { |
| 92 | 107 | //请求Body,不携带签名名称时,signature请填null |
| 93 | 108 | String body = buildRequestBody(sender, receiver, templateId, templateParas, statusCallBack, null); |
| 94 | 109 | if (null == body || body.isEmpty()) { |
| 95 | - LOGGER.warn("body is null."); | |
| 96 | 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 | 128 | HttpUriRequest postMethod = RequestBuilder.post() |
| 111 | 129 | .setUri(url) |
| 112 | - .setEntity(new StringEntity(request.getBody(), StandardCharsets.UTF_8)) | |
| 130 | + .setEntity(new StringEntity(body, StandardCharsets.UTF_8)) | |
| 113 | 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 | 134 | .build(); |
| 117 | 135 | CloseableHttpClient client = HttpClientBuilder.create().build(); |
| 118 | - | |
| 119 | 136 | HttpResponse response = client.execute(postMethod); |
| 137 | + | |
| 120 | 138 | return new SmsSendRespDTO().setSuccess(Objects.equals(response.getStatusLine().getReasonPhrase(), API_CODE_SUCCESS)).setSerialNo(Integer.toString(response.getStatusLine().getStatusCode())) |
| 121 | 139 | .setApiRequestId(null).setApiCode(null).setApiMsg(null); |
| 122 | 140 | } |
| ... | ... | @@ -141,7 +159,6 @@ public class HuaweiSmsClient extends AbstractSmsClient { |
| 141 | 159 | |
| 142 | 160 | private static void appendToBody(StringBuilder body, String key, String val) throws UnsupportedEncodingException { |
| 143 | 161 | if (null != val && !val.isEmpty()) { |
| 144 | - LOGGER.info("Print appendToBody: {}:{}", key, val); | |
| 145 | 162 | body.append(key).append(URLEncoder.encode(val, "UTF-8")); |
| 146 | 163 | } |
| 147 | 164 | } |
| ... | ... | @@ -181,20 +198,17 @@ public class HuaweiSmsClient extends AbstractSmsClient { |
| 181 | 198 | /** |
| 182 | 199 | * 短信资源的更新时间,通常为短信平台接收短信状态报告的时间 |
| 183 | 200 | */ |
| 184 | - @JsonProperty("updateTime") | |
| 185 | 201 | @JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT) |
| 186 | 202 | private LocalDateTime updateTime; |
| 187 | 203 | |
| 188 | 204 | /** |
| 189 | 205 | * 短信状态报告枚举值 |
| 190 | 206 | */ |
| 191 | - @JsonProperty("status") | |
| 192 | 207 | private String status; |
| 193 | 208 | |
| 194 | 209 | /** |
| 195 | 210 | * 发送短信成功时返回的短信唯一标识。 |
| 196 | 211 | */ |
| 197 | - @JsonProperty("smsMsgId") | |
| 198 | 212 | private String smsMsgId; |
| 199 | 213 | } |
| 200 | 214 | ... | ... |