Commit dfc92c94509436416a3912709e34604f4c5ece89

Authored by YunaiV
1 parent 3ca2981a

fix:【system 系统功能】修复阿里云sms api缺少参数的问题 !159

yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/client/impl/AliyunSmsClient.java
@@ -136,15 +136,20 @@ public class AliyunSmsClient extends AbstractSmsClient { @@ -136,15 +136,20 @@ public class AliyunSmsClient extends AbstractSmsClient {
136 .map(entry -> percentCode(entry.getKey()) + "=" + percentCode(String.valueOf(entry.getValue()))) 136 .map(entry -> percentCode(entry.getKey()) + "=" + percentCode(String.valueOf(entry.getValue())))
137 .collect(Collectors.joining("&")); 137 .collect(Collectors.joining("&"));
138 138
139 - // 2.1 请求 Header 139 + // 2. 请求 Body
  140 + String requestBody = ""; // 短信 API 为 RPC 接口,query parameters 在 uri 中拼接,因此 request body 如果没有特殊要求,设置为空
  141 + String hashedRequestPayload = DigestUtil.sha256Hex(requestBody);
  142 +
  143 + // 3.1 请求 Header
140 TreeMap<String, String> headers = new TreeMap<>(); 144 TreeMap<String, String> headers = new TreeMap<>();
141 headers.put("host", HOST); 145 headers.put("host", HOST);
142 headers.put("x-acs-version", VERSION); 146 headers.put("x-acs-version", VERSION);
143 headers.put("x-acs-action", apiName); 147 headers.put("x-acs-action", apiName);
144 headers.put("x-acs-date", FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ss'Z'", TimeZone.getTimeZone("GMT")).format(new Date())); 148 headers.put("x-acs-date", FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ss'Z'", TimeZone.getTimeZone("GMT")).format(new Date()));
145 headers.put("x-acs-signature-nonce", IdUtil.randomUUID()); 149 headers.put("x-acs-signature-nonce", IdUtil.randomUUID());
  150 + headers.put("x-acs-content-sha256", hashedRequestPayload);
146 151
147 - // 2.2 构建签名 Header 152 + // 3.2 构建签名 Header
148 StringBuilder canonicalHeaders = new StringBuilder(); // 构造请求头,多个规范化消息头,按照消息头名称(小写)的字符代码顺序以升序排列后拼接在一起 153 StringBuilder canonicalHeaders = new StringBuilder(); // 构造请求头,多个规范化消息头,按照消息头名称(小写)的字符代码顺序以升序排列后拼接在一起
149 StringBuilder signedHeadersBuilder = new StringBuilder(); // 已签名消息头列表,多个请求头名称(小写)按首字母升序排列并以英文分号(;)分隔 154 StringBuilder signedHeadersBuilder = new StringBuilder(); // 已签名消息头列表,多个请求头名称(小写)按首字母升序排列并以英文分号(;)分隔
150 headers.entrySet().stream().filter(entry -> entry.getKey().toLowerCase().startsWith("x-acs-") 155 headers.entrySet().stream().filter(entry -> entry.getKey().toLowerCase().startsWith("x-acs-")
@@ -157,13 +162,13 @@ public class AliyunSmsClient extends AbstractSmsClient { @@ -157,13 +162,13 @@ public class AliyunSmsClient extends AbstractSmsClient {
157 }); 162 });
158 String signedHeaders = signedHeadersBuilder.substring(0, signedHeadersBuilder.length() - 1); 163 String signedHeaders = signedHeadersBuilder.substring(0, signedHeadersBuilder.length() - 1);
159 164
160 - // 3. 请求 Body  
161 - String requestBody = ""; // 短信 API 为 RPC 接口,query parameters 在 uri 中拼接,因此 request body 如果没有特殊要求,设置为空。  
162 - String hashedRequestBody = DigestUtil.sha256Hex(requestBody);  
163 -  
164 // 4. 构建 Authorization 签名 165 // 4. 构建 Authorization 签名
165 - String canonicalRequest = "POST" + "\n" + "/" + "\n" + queryString + "\n"  
166 - + canonicalHeaders + "\n" + signedHeaders + "\n" + hashedRequestBody; 166 + String canonicalRequest = "POST" + "\n" +
  167 + "/" + "\n" +
  168 + queryString + "\n" +
  169 + canonicalHeaders + "\n" +
  170 + signedHeaders + "\n" +
  171 + hashedRequestPayload;
167 String hashedCanonicalRequest = DigestUtil.sha256Hex(canonicalRequest); 172 String hashedCanonicalRequest = DigestUtil.sha256Hex(canonicalRequest);
168 String stringToSign = "ACS3-HMAC-SHA256" + "\n" + hashedCanonicalRequest; 173 String stringToSign = "ACS3-HMAC-SHA256" + "\n" + hashedCanonicalRequest;
169 String signature = SecureUtil.hmacSha256(properties.getApiSecret()).digestHex(stringToSign); // 计算签名 174 String signature = SecureUtil.hmacSha256(properties.getApiSecret()).digestHex(stringToSign); // 计算签名
@@ -184,7 +189,7 @@ public class AliyunSmsClient extends AbstractSmsClient { @@ -184,7 +189,7 @@ public class AliyunSmsClient extends AbstractSmsClient {
184 @SneakyThrows 189 @SneakyThrows
185 private static String percentCode(String str) { 190 private static String percentCode(String str) {
186 Assert.notNull(str, "str 不能为空"); 191 Assert.notNull(str, "str 不能为空");
187 - return HttpUtils.encodeUtf8(str) 192 + return URLEncoder.encode(str, StandardCharsets.UTF_8.name())
188 .replace("+", "%20") // 加号 "+" 被替换为 "%20" 193 .replace("+", "%20") // 加号 "+" 被替换为 "%20"
189 .replace("*", "%2A") // 星号 "*" 被替换为 "%2A" 194 .replace("*", "%2A") // 星号 "*" 被替换为 "%2A"
190 .replace("%7E", "~"); // 波浪号 "%7E" 被替换为 "~" 195 .replace("%7E", "~"); // 波浪号 "%7E" 被替换为 "~"