From 2156d2759b1f8457a8b1e8f21a6164fa7ae06efc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=98=BF=E6=B2=90?= Date: Tue, 25 Jun 2024 17:16:41 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../net/maku/message/sms/HuaweiSmsStrategy.java | 195 --------------------- .../main/java/net/maku/sms/HuaweiSmsStrategy.java | 195 +++++++++++++++++++++ 2 files changed, 195 insertions(+), 195 deletions(-) delete mode 100644 maku-boot-module/maku-module-message/src/main/java/net/maku/message/sms/HuaweiSmsStrategy.java create mode 100644 maku-boot-system/src/main/java/net/maku/sms/HuaweiSmsStrategy.java diff --git a/maku-boot-module/maku-module-message/src/main/java/net/maku/message/sms/HuaweiSmsStrategy.java b/maku-boot-module/maku-module-message/src/main/java/net/maku/message/sms/HuaweiSmsStrategy.java deleted file mode 100644 index 34cdc7c..0000000 --- a/maku-boot-module/maku-module-message/src/main/java/net/maku/message/sms/HuaweiSmsStrategy.java +++ /dev/null @@ -1,195 +0,0 @@ -package net.maku.message.sms; - -import cn.hutool.core.io.IoUtil; -import cn.hutool.core.map.MapUtil; -import cn.hutool.core.util.CharsetUtil; -import lombok.Data; -import net.maku.framework.common.exception.ServerException; -import net.maku.framework.common.utils.JsonUtils; -import net.maku.message.sms.config.SmsConfig; -import org.apache.commons.lang3.StringUtils; -import org.springframework.http.HttpStatus; - -import javax.net.ssl.*; -import java.io.UnsupportedEncodingException; -import java.net.URL; -import java.net.URLEncoder; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.security.cert.X509Certificate; -import java.text.SimpleDateFormat; -import java.util.*; - -/** - * 华为云短信 - * - * @author 阿沐 babamu@126.com - * MAKU - */ -public class HuaweiSmsStrategy implements SmsStrategy { - // 无需修改,用于格式化鉴权头域,给"X-WSSE"参数赋值 - private static final String WSSE_HEADER_FORMAT = "UsernameToken Username=\"%s\",PasswordDigest=\"%s\",Nonce=\"%s\",Created=\"%s\""; - // 无需修改,用于格式化鉴权头域,给"Authorization"参数赋值 - private static final String AUTH_HEADER_VALUE = "WSSE realm=\"SDP\",profile=\"UsernameToken\",type=\"Appkey\""; - private final SmsConfig smsConfig; - - public HuaweiSmsStrategy(SmsConfig smsConfig) { - this.smsConfig = smsConfig; - } - - @Override - public void send(String mobile, Map params) { - // 有参数则设置 - String templateParas = null; - if (MapUtil.isNotEmpty(params)) { - templateParas = JsonUtils.toJsonString(params.values().toArray(new String[0])); - } - - // 请求Body,不携带签名名称时,signature请填null - String body = buildRequestBody(smsConfig.getSenderId(), "+86" + mobile, smsConfig.getTemplateId(), templateParas, null, smsConfig.getSignName()); - if (StringUtils.isBlank(body)) { - throw new ServerException("body is null."); - } - - // 请求Headers中的X-WSSE参数值 - String wsseHeader = buildWsseHeader(smsConfig.getAccessKey(), smsConfig.getSecretKey()); - if (StringUtils.isBlank(wsseHeader)) { - throw new ServerException("wsse header is null."); - } - - try { - // 使用 https - trustAllHttpsCertificates(); - - // 接入地址 - String url = smsConfig.getUrl() + "/sms/batchSendSms/v1"; - URL realUrl = new URL(url); - HttpsURLConnection connection = (HttpsURLConnection) realUrl.openConnection(); - HostnameVerifier hv = (hostname, session) -> true; - connection.setHostnameVerifier(hv); - connection.setDoOutput(true); - connection.setDoInput(true); - connection.setUseCaches(true); - connection.setRequestMethod("POST"); - connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); - connection.setRequestProperty("Authorization", AUTH_HEADER_VALUE); - connection.setRequestProperty("X-WSSE", wsseHeader); - connection.connect(); - - IoUtil.writeUtf8(connection.getOutputStream(), true, body); - - int status = connection.getResponseCode(); - if (status == HttpStatus.OK.value()) { - String response = IoUtil.read(connection.getInputStream(), CharsetUtil.CHARSET_UTF_8); - HuaweiSmsResult result = JsonUtils.parseObject(response, HuaweiSmsResult.class); - - // 短信是否发送成功 - assert result != null; - if (!"000000".equals(result.code)) { - throw new ServerException(result.description); - } - } else { //400 401 - throw new ServerException(IoUtil.read(connection.getErrorStream(), CharsetUtil.CHARSET_UTF_8)); - } - } catch (Exception e) { - throw new ServerException(e.getMessage()); - } - } - - /** - * 构造请求Body体 - * - * @param signature | 签名名称,使用国内短信通用模板时填写 - */ - static String buildRequestBody(String sender, String receiver, String templateId, String templateParas, - String statusCallBack, String signature) { - if (null == sender || null == receiver || null == templateId || sender.isEmpty() || receiver.isEmpty() - || templateId.isEmpty()) { - throw new ServerException("buildRequestBody(): sender, receiver or templateId is null."); - } - Map map = new HashMap<>(); - - map.put("from", sender); - map.put("to", receiver); - map.put("templateId", templateId); - if (null != templateParas && !templateParas.isEmpty()) { - map.put("templateParas", templateParas); - } - if (null != statusCallBack && !statusCallBack.isEmpty()) { - map.put("statusCallback", statusCallBack); - } - if (null != signature && !signature.isEmpty()) { - map.put("signature", signature); - } - - StringBuilder sb = new StringBuilder(); - String temp = ""; - - for (String s : map.keySet()) { - try { - temp = URLEncoder.encode(map.get(s), "UTF-8"); - } catch (UnsupportedEncodingException e) { - e.printStackTrace(); - } - sb.append(s).append("=").append(temp).append("&"); - } - - return sb.deleteCharAt(sb.length() - 1).toString(); - } - - /** - * 构造X-WSSE参数值 - */ - static String buildWsseHeader(String appKey, String appSecret) { - if (null == appKey || null == appSecret || appKey.isEmpty() || appSecret.isEmpty()) { - throw new ServerException("buildWsseHeader(): appKey or appSecret is null."); - } - SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); - String time = sdf.format(new Date()); - String nonce = UUID.randomUUID().toString().replace("-", ""); - - MessageDigest md; - byte[] passwordDigest = null; - - try { - md = MessageDigest.getInstance("SHA-256"); - md.update((nonce + time + appSecret).getBytes()); - passwordDigest = md.digest(); - } catch (NoSuchAlgorithmException e) { - e.printStackTrace(); - } - - String passwordDigestBase64Str = Base64.getEncoder().encodeToString(passwordDigest); - - return String.format(WSSE_HEADER_FORMAT, appKey, passwordDigestBase64Str, nonce, time); - } - - static void trustAllHttpsCertificates() throws Exception { - TrustManager[] trustAllCerts = new TrustManager[]{ - new X509TrustManager() { - public void checkClientTrusted(X509Certificate[] chain, String authType) { - - } - - public void checkServerTrusted(X509Certificate[] chain, String authType) { - - } - - public X509Certificate[] getAcceptedIssuers() { - return null; - } - } - }; - SSLContext sc = SSLContext.getInstance("SSL"); - sc.init(null, trustAllCerts, null); - HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); - } - - @Data - static class HuaweiSmsResult { - // code为000000,表示成功 - private String code; - private String description; - private List result; - } -} diff --git a/maku-boot-system/src/main/java/net/maku/sms/HuaweiSmsStrategy.java b/maku-boot-system/src/main/java/net/maku/sms/HuaweiSmsStrategy.java new file mode 100644 index 0000000..e59d32d --- /dev/null +++ b/maku-boot-system/src/main/java/net/maku/sms/HuaweiSmsStrategy.java @@ -0,0 +1,195 @@ +package net.maku.sms; + +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.CharsetUtil; +import lombok.Data; +import net.maku.framework.common.exception.ServerException; +import net.maku.framework.common.utils.JsonUtils; +import net.maku.sms.config.SmsConfig; +import org.apache.commons.lang3.StringUtils; +import org.springframework.http.HttpStatus; + +import javax.net.ssl.*; +import java.io.UnsupportedEncodingException; +import java.net.URL; +import java.net.URLEncoder; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.cert.X509Certificate; +import java.text.SimpleDateFormat; +import java.util.*; + +/** + * 华为云短信 + * + * @author 阿沐 babamu@126.com + * MAKU + */ +public class HuaweiSmsStrategy implements SmsStrategy { + // 无需修改,用于格式化鉴权头域,给"X-WSSE"参数赋值 + private static final String WSSE_HEADER_FORMAT = "UsernameToken Username=\"%s\",PasswordDigest=\"%s\",Nonce=\"%s\",Created=\"%s\""; + // 无需修改,用于格式化鉴权头域,给"Authorization"参数赋值 + private static final String AUTH_HEADER_VALUE = "WSSE realm=\"SDP\",profile=\"UsernameToken\",type=\"Appkey\""; + private final SmsConfig smsConfig; + + public HuaweiSmsStrategy(SmsConfig smsConfig) { + this.smsConfig = smsConfig; + } + + @Override + public void send(String mobile, Map params) { + // 有参数则设置 + String templateParas = null; + if (MapUtil.isNotEmpty(params)) { + templateParas = JsonUtils.toJsonString(params.values().toArray(new String[0])); + } + + // 请求Body,不携带签名名称时,signature请填null + String body = buildRequestBody(smsConfig.getSenderId(), "+86" + mobile, smsConfig.getTemplateId(), templateParas, null, smsConfig.getSignName()); + if (StringUtils.isBlank(body)) { + throw new ServerException("body is null."); + } + + // 请求Headers中的X-WSSE参数值 + String wsseHeader = buildWsseHeader(smsConfig.getAccessKey(), smsConfig.getSecretKey()); + if (StringUtils.isBlank(wsseHeader)) { + throw new ServerException("wsse header is null."); + } + + try { + // 使用 https + trustAllHttpsCertificates(); + + // 接入地址 + String url = smsConfig.getUrl() + "/sms/batchSendSms/v1"; + URL realUrl = new URL(url); + HttpsURLConnection connection = (HttpsURLConnection) realUrl.openConnection(); + HostnameVerifier hv = (hostname, session) -> true; + connection.setHostnameVerifier(hv); + connection.setDoOutput(true); + connection.setDoInput(true); + connection.setUseCaches(true); + connection.setRequestMethod("POST"); + connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); + connection.setRequestProperty("Authorization", AUTH_HEADER_VALUE); + connection.setRequestProperty("X-WSSE", wsseHeader); + connection.connect(); + + IoUtil.writeUtf8(connection.getOutputStream(), true, body); + + int status = connection.getResponseCode(); + if (status == HttpStatus.OK.value()) { + String response = IoUtil.read(connection.getInputStream(), CharsetUtil.CHARSET_UTF_8); + HuaweiSmsResult result = JsonUtils.parseObject(response, HuaweiSmsResult.class); + + // 短信是否发送成功 + assert result != null; + if (!"000000".equals(result.code)) { + throw new ServerException(result.description); + } + } else { //400 401 + throw new ServerException(IoUtil.read(connection.getErrorStream(), CharsetUtil.CHARSET_UTF_8)); + } + } catch (Exception e) { + throw new ServerException(e.getMessage()); + } + } + + /** + * 构造请求Body体 + * + * @param signature | 签名名称,使用国内短信通用模板时填写 + */ + static String buildRequestBody(String sender, String receiver, String templateId, String templateParas, + String statusCallBack, String signature) { + if (null == sender || null == receiver || null == templateId || sender.isEmpty() || receiver.isEmpty() + || templateId.isEmpty()) { + throw new ServerException("buildRequestBody(): sender, receiver or templateId is null."); + } + Map map = new HashMap<>(); + + map.put("from", sender); + map.put("to", receiver); + map.put("templateId", templateId); + if (null != templateParas && !templateParas.isEmpty()) { + map.put("templateParas", templateParas); + } + if (null != statusCallBack && !statusCallBack.isEmpty()) { + map.put("statusCallback", statusCallBack); + } + if (null != signature && !signature.isEmpty()) { + map.put("signature", signature); + } + + StringBuilder sb = new StringBuilder(); + String temp = ""; + + for (String s : map.keySet()) { + try { + temp = URLEncoder.encode(map.get(s), "UTF-8"); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + sb.append(s).append("=").append(temp).append("&"); + } + + return sb.deleteCharAt(sb.length() - 1).toString(); + } + + /** + * 构造X-WSSE参数值 + */ + static String buildWsseHeader(String appKey, String appSecret) { + if (null == appKey || null == appSecret || appKey.isEmpty() || appSecret.isEmpty()) { + throw new ServerException("buildWsseHeader(): appKey or appSecret is null."); + } + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); + String time = sdf.format(new Date()); + String nonce = UUID.randomUUID().toString().replace("-", ""); + + MessageDigest md; + byte[] passwordDigest = null; + + try { + md = MessageDigest.getInstance("SHA-256"); + md.update((nonce + time + appSecret).getBytes()); + passwordDigest = md.digest(); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } + + String passwordDigestBase64Str = Base64.getEncoder().encodeToString(passwordDigest); + + return String.format(WSSE_HEADER_FORMAT, appKey, passwordDigestBase64Str, nonce, time); + } + + static void trustAllHttpsCertificates() throws Exception { + TrustManager[] trustAllCerts = new TrustManager[]{ + new X509TrustManager() { + public void checkClientTrusted(X509Certificate[] chain, String authType) { + + } + + public void checkServerTrusted(X509Certificate[] chain, String authType) { + + } + + public X509Certificate[] getAcceptedIssuers() { + return null; + } + } + }; + SSLContext sc = SSLContext.getInstance("SSL"); + sc.init(null, trustAllCerts, null); + HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); + } + + @Data + static class HuaweiSmsResult { + // code为000000,表示成功 + private String code; + private String description; + private List result; + } +}