Ver código fonte

!2 增加了加签机器人配置
* Merge remote-tracking branch 'origin/master'
* 增加对加签群机器人支持,详见Demo配置项

dgatiger 5 anos atrás
pai
commit
88960517ea

+ 2 - 2
dingtalk-robot-demo/pom.xml

@@ -18,12 +18,12 @@
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-test</artifactId>
-            <version>2.1.4.RELEASE</version>
+            <version>2.2.5.RELEASE</version>
         </dependency>
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-web</artifactId>
-            <version>2.1.4.RELEASE</version>
+            <version>2.2.5.RELEASE</version>
         </dependency>
     </dependencies>
 

+ 5 - 1
dingtalk-robot-demo/src/main/resources/application.yaml

@@ -1,3 +1,7 @@
 dingtalk:
   robot:
-    webhook: https://oapi.dingtalk.com/robot/send?access_token=4f2299201911623ee5e30770a37e31c44dc1af1ba69321b71fd12523ab6d596d
+    prefix: https://oapi.dingtalk.com/robot/send
+    access_token: change-to-your-access-token
+    secret:
+      secret_enabled: false
+      secret_token: change-to-your-secret-token

+ 1 - 1
spring-boot-dingtalk-robot-starter/pom.xml

@@ -23,7 +23,7 @@
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-web</artifactId>
-            <version>2.1.4.RELEASE</version>
+            <version>2.2.5.RELEASE</version>
             <optional>true</optional>
         </dependency>
     </dependencies>

+ 103 - 24
spring-boot-dingtalk-robot-starter/src/main/java/cn/snowheart/dingtalk/robot/starter/client/DingTalkRobotClient.java

@@ -1,17 +1,12 @@
 package cn.snowheart.dingtalk.robot.starter.client;
 
-import cn.snowheart.dingtalk.robot.starter.entity.ActionCardButton;
-import cn.snowheart.dingtalk.robot.starter.entity.ActionCardMessage;
-import cn.snowheart.dingtalk.robot.starter.entity.BaseMessage;
-import cn.snowheart.dingtalk.robot.starter.entity.DingTalkResponse;
-import cn.snowheart.dingtalk.robot.starter.entity.FeedCardMessage;
-import cn.snowheart.dingtalk.robot.starter.entity.FeedCardMessageItem;
-import cn.snowheart.dingtalk.robot.starter.entity.LinkMessage;
-import cn.snowheart.dingtalk.robot.starter.entity.MarkdownMessage;
-import cn.snowheart.dingtalk.robot.starter.entity.TextMessage;
+import cn.snowheart.dingtalk.robot.starter.entity.*;
 import cn.snowheart.dingtalk.robot.starter.exception.DingTalkException;
 import cn.snowheart.dingtalk.robot.starter.type.HideAvatarType;
 import cn.snowheart.dingtalk.robot.starter.type.ResponseCodeType;
+import org.apache.tomcat.util.codec.binary.Base64;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.beans.factory.annotation.Value;
@@ -20,6 +15,11 @@ import org.springframework.http.HttpHeaders;
 import org.springframework.http.MediaType;
 import org.springframework.web.client.RestTemplate;
 
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLEncoder;
 import java.util.List;
 import java.util.Map;
 
@@ -30,22 +30,81 @@ import java.util.Map;
  * @version 1.0.0
  */
 public class DingTalkRobotClient {
+    private final static Logger log = LoggerFactory.getLogger(DingTalkRobotClient.class);
 
     @Autowired
     @Qualifier("dingTalkRobotRestTemplate")
     private RestTemplate restTemplate;
 
     /**
-     * 钉钉机器人WebHook地址的默认前缀,供AccessToken调用方式使用
+     * 钉钉机器人WebHook地址的默认前缀
      */
-    @Value("${dingtalk.robot.prefix:https://oapi.dingtalk.com/robot/send?access_token=}")
-    private String defaultUrlPrefix;
+    @Value("${dingtalk.robot.prefix:https://oapi.dingtalk.com/robot/send}")
+    private String urlPrefix;
+    /**
+     * 钉钉机器人WebHook地址的access_token
+     */
+    @Value("${dingtalk.robot.access_token}")
+    private String accessToken;
+
+    /**
+     * 钉钉机器人是否启用加签,默认false,启用加签需设置secret_token
+     */
+    @Value("${dingtalk.robot.secret.secret_enabled:false}")
+    private boolean secretEnable;
+
+    /**
+     * 钉钉机器人WebHook地址的secret_token,群机器人加签用
+     */
+    @Value("${dingtalk.robot.secret.secret_token:null}")
+    private String secretToken;
+
+    /**
+     * Gets default webhook.
+     * @return the default webhook
+     */
+    public String getDefaultWebhook() {
+        return getWebhook(accessToken);
+    }
+
+    /**
+     * Gets webhook.
+     * @param accessToken the access token
+     * @return the webhook
+     */
+    public String getWebhook(String accessToken) {
+        String url = urlPrefix + "?access_token=" + accessToken;
+        //若启用加签加上时间戳跟签名串
+        if (secretEnable) {
+            Long timestamp = System.currentTimeMillis();
+            url += "&timestamp=" + timestamp
+                    + "&sign=" + getSign(secretToken, timestamp);
+        }
+        log.debug(url);
+        return url;
+    }
 
     /**
-     * 钉钉机器人的WebHook地址
+     * 计算签名
+     * 参考:https://ding-doc.dingtalk.com/doc#/serverapi2/qf2nxq/9e91d73c
+     * @param secret    密钥,机器人安全设置页面,加签一栏下面显示的SEC开头的字符
+     * @param @timestamp
+     * @return
      */
-    @Value("${dingtalk.robot.webhook}")
-    private String defaultWebhook;
+    static String getSign(String secret, Long timestamp) {
+        try {
+            String stringToSign = timestamp + "\n" + secret;
+            Mac mac = Mac.getInstance("HmacSHA256");
+            mac.init(new SecretKeySpec(secret.getBytes("UTF-8"), "HmacSHA256"));
+            byte[] signData = mac.doFinal(stringToSign.getBytes("UTF-8"));
+            String sign = URLEncoder.encode(new String(Base64.encodeBase64(signData)), "UTF-8");
+            log.debug("【发送钉钉群消息】获取到签名sign = {}", sign);
+            return sign;
+        } catch (Exception e) {
+            log.error("【发送钉钉群消息】计算签名异常,errMsg = {}", e);
+            return null;
+        }
+    }
 
     /**
      * 支持外部传入WebHook地址的方式发送消息
@@ -55,19 +114,39 @@ public class DingTalkRobotClient {
      * @return
      */
     public DingTalkResponse sendMessageByURL(String url, BaseMessage message) {
+        URL actualUrl;
+        try {
+            actualUrl = new URL(url);
+        } catch (MalformedURLException e) {
+            throw new RuntimeException("URL创建报错!");
+        }
+        return sendMessageByURL(actualUrl, message);
+    }
+
+    /**
+     * 支持外部传入WebHook地址的方式发送消息
+     *
+     * @param url
+     * @param message
+     * @return
+     */
+    public DingTalkResponse sendMessageByURL(URL url, BaseMessage message) {
 
         HttpHeaders headers = new HttpHeaders();
         headers.setContentType(MediaType.APPLICATION_JSON);
         HttpEntity<Map> entity = new HttpEntity<>(message.toMessageMap(), headers);
+        try {
+            DingTalkResponse dingTalkResponse =
+                    restTemplate.postForObject(url.toURI(), entity, DingTalkResponse.class);
 
-        DingTalkResponse dingTalkResponse =
-                restTemplate.postForObject(url, entity, DingTalkResponse.class);
-
-        if (!ResponseCodeType.OK.getValue().equals(dingTalkResponse.getErrcode())) {
-            throw new DingTalkException(dingTalkResponse.getErrcode(), dingTalkResponse.getErrmsg());
+            if (!ResponseCodeType.OK.getValue().equals(dingTalkResponse.getErrcode())) {
+                throw new DingTalkException(dingTalkResponse.getErrcode(), dingTalkResponse.getErrmsg());
+            }
+            return dingTalkResponse;
+        } catch (Exception e) {
+            log.error(e.fillInStackTrace().toString());
+            return null;
         }
-
-        return dingTalkResponse;
     }
 
     /**
@@ -78,7 +157,7 @@ public class DingTalkRobotClient {
      * @return
      */
     public DingTalkResponse sendMessageByAccessToken(String accessToken, BaseMessage message) {
-        return this.sendMessageByURL(defaultUrlPrefix + accessToken, message);
+        return this.sendMessageByURL(getWebhook(accessToken), message);
     }
 
     /**
@@ -88,7 +167,7 @@ public class DingTalkRobotClient {
      * @return
      */
     public DingTalkResponse sendMessage(BaseMessage message) {
-        return this.sendMessageByURL(defaultWebhook, message);
+        return this.sendMessageByURL(getDefaultWebhook(), message);
     }
 
     /**