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,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 |