瀏覽代碼

钉钉扫描登录接口demo编写

yusm 1 周之前
父節點
當前提交
da7805db1b

+ 4 - 0
fhKeeper/formulahousekeeper/management-crm/src/main/java/com/management/platform/entity/Company.java

@@ -4,9 +4,11 @@ import com.baomidou.mybatisplus.annotation.IdType;
 import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.extension.activerecord.Model;
+import com.fasterxml.jackson.annotation.JsonFormat;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.experimental.Accessors;
+import org.springframework.format.annotation.DateTimeFormat;
 
 import java.io.Serializable;
 import java.time.LocalDateTime;
@@ -47,6 +49,8 @@ public class Company extends Model<Company> {
     /**
      * 会员到期时间
      */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
     @TableField("expiration_date")
     private LocalDateTime expirationDate;
 

+ 52 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/DingTalkController.java

@@ -0,0 +1,52 @@
+package com.management.platform.controller;
+
+import com.management.platform.entity.DingTalkConfig;
+
+import com.management.platform.entity.DingTalkUserInfo;
+import com.management.platform.service.impl.AuthService;
+import com.management.platform.service.impl.DingTalkService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+@RestController
+@RequestMapping("/dingtalk")
+public class DingTalkController {
+    
+    private final DingTalkConfig dingTalkConfig;
+    private final DingTalkService dingTalkService;
+    private final AuthService authService;
+
+    @Autowired
+    public DingTalkController(DingTalkConfig dingTalkConfig, 
+                           DingTalkService dingTalkService,
+                           AuthService authService) {
+        this.dingTalkConfig = dingTalkConfig;
+        this.dingTalkService = dingTalkService;
+        this.authService = authService;
+    }
+
+    /**
+     * 钉钉回调接口
+     */
+    @GetMapping("/callback")
+    public ResponseEntity<?> callback(@RequestParam("code") String code,
+                                      @RequestParam("state") String state,
+                                      HttpServletResponse response) throws IOException {
+        // 1. 用code换取用户信息
+        DingTalkUserInfo userInfo = dingTalkService.getUserInfoByCode(code);
+        
+        // 2. 业务系统登录逻辑
+        String token = "";
+        
+        // 3. 重定向到前端并携带token
+        response.sendRedirect(dingTalkConfig.getRedirectUri() + "?token=" + token);
+        return ResponseEntity.ok().build();
+    }
+}

+ 14 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/DingTalkConfig.java

@@ -0,0 +1,14 @@
+package com.management.platform.entity;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+@Data
+@Configuration
+@ConfigurationProperties(prefix = "dingtalk")
+public class DingTalkConfig {
+    private String appId;
+    private String appSecret;
+    private String redirectUri;
+}

+ 12 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/DingTalkUserInfo.java

@@ -0,0 +1,12 @@
+package com.management.platform.entity;
+
+import lombok.Data;
+
+@Data
+public class DingTalkUserInfo {
+    private String unionId;    // 用户唯一标识
+    private String userId;     // 用户ID
+    private String name;       // 用户姓名
+    private String avatar;     // 头像URL
+    private String mobile;     // 手机号
+}

+ 19 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/AuthService.java

@@ -0,0 +1,19 @@
+package com.management.platform.service.impl;
+
+import com.management.platform.entity.DingTalkUserInfo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+public class AuthService {
+    
+
+    /**
+     * 钉钉登录处理
+     */
+    public String dingTalkLogin(DingTalkUserInfo dingTalkUserInfo) {
+        return "";
+    }
+    
+
+}

+ 153 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/DingTalkService.java

@@ -0,0 +1,153 @@
+package com.management.platform.service.impl;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.management.platform.entity.DingTalkConfig;
+import com.management.platform.entity.DingTalkUserInfo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Service;
+import org.springframework.web.client.RestTemplate;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+import java.io.IOException;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.util.Base64;
+import java.util.HashMap;
+import java.util.Map;
+
+@Service
+public class DingTalkService {
+    
+    private final DingTalkConfig dingTalkConfig;
+    private final RestTemplate restTemplate;
+    
+    private static final String GET_USER_INFO_URL = 
+        "https://oapi.dingtalk.com/sns/getuserinfo_bycode";
+    private static final String GET_USER_DETAIL_URL = 
+        "https://oapi.dingtalk.com/topapi/v2/user/getuserinfo";
+
+    @Autowired
+    public DingTalkService(DingTalkConfig dingTalkConfig, RestTemplate restTemplate) {
+        this.dingTalkConfig = dingTalkConfig;
+        this.restTemplate = restTemplate;
+    }
+
+    /**
+     * 使用临时授权码获取用户信息
+     */
+    public DingTalkUserInfo getUserInfoByCode(String code) {
+        // 1. 构造请求参数
+        String timestamp = String.valueOf(System.currentTimeMillis());
+        String signature = generateSignature(timestamp);
+        
+        // 2. 构造请求体
+        Map<String, String> requestBody = new HashMap<>();
+        requestBody.put("tmp_auth_code", code);
+        
+        // 3. 构造请求URL
+        String url = String.format("%s?accessKey=%s&timestamp=%s&signature=%s",
+                GET_USER_INFO_URL, dingTalkConfig.getAppId(), timestamp, signature);
+        
+        // 4. 发送请求
+        ResponseEntity<String> response = restTemplate.postForEntity(
+                url, 
+                new HttpEntity<>(requestBody, buildHeaders()),
+                String.class);
+        
+        // 5. 解析响应
+        JsonNode jsonNode = parseResponse(response.getBody());
+        JsonNode userInfo = jsonNode.get("user_info");
+        
+        // 6. 获取用户详细信息
+        String unionId = userInfo.get("unionid").asText();
+        return getUserDetail(unionId);
+    }
+    
+    /**
+     * 获取用户详细信息
+     */
+    private DingTalkUserInfo getUserDetail(String unionId) {
+        // 1. 获取access_token
+        String accessToken = getAccessToken();
+        
+        // 2. 构造请求体
+        Map<String, Object> requestBody = new HashMap<>();
+        requestBody.put("unionid", unionId);
+        
+        // 3. 发送请求
+        ResponseEntity<String> response = restTemplate.postForEntity(
+                GET_USER_DETAIL_URL + "?access_token=" + accessToken,
+                new HttpEntity<>(requestBody, buildHeaders()),
+                String.class);
+        
+        // 4. 解析响应
+        JsonNode jsonNode = parseResponse(response.getBody());
+        JsonNode result = jsonNode.get("result");
+        
+        DingTalkUserInfo userInfo = new DingTalkUserInfo();
+        userInfo.setUnionId(unionId);
+        userInfo.setUserId(result.get("userid").asText());
+        userInfo.setName(result.get("name").asText());
+        userInfo.setAvatar(result.get("avatar").asText());
+        userInfo.setMobile(result.get("mobile").asText());
+        
+        return userInfo;
+    }
+    
+    /**
+     * 获取access_token
+     */
+    private String getAccessToken() {
+        String url = String.format(
+                "https://oapi.dingtalk.com/gettoken?appkey=%s&appsecret=%s",
+                dingTalkConfig.getAppId(), dingTalkConfig.getAppSecret());
+        
+        JsonNode jsonNode = parseResponse(restTemplate.getForObject(url, String.class));
+        return jsonNode.get("access_token").asText();
+    }
+    
+    /**
+     * 生成签名
+     */
+    private String generateSignature(String timestamp) {
+        try {
+            String stringToSign = timestamp + "\n" + dingTalkConfig.getAppSecret();
+            Mac mac = Mac.getInstance("HmacSHA256");
+            mac.init(new SecretKeySpec(dingTalkConfig.getAppSecret().getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
+            byte[] signData = mac.doFinal(stringToSign.getBytes(StandardCharsets.UTF_8));
+            return URLEncoder.encode(Base64.getEncoder().encodeToString(signData), "UTF-8");
+        } catch (Exception e) {
+            throw new RuntimeException("生成签名失败", e);
+        }
+    }
+    
+    /**
+     * 构建请求头
+     */
+    private HttpHeaders buildHeaders() {
+        HttpHeaders headers = new HttpHeaders();
+        headers.setContentType(MediaType.APPLICATION_JSON);
+        return headers;
+    }
+    
+    /**
+     * 解析响应
+     */
+    private JsonNode parseResponse(String response) {
+        try {
+            JsonNode jsonNode = new ObjectMapper().readTree(response);
+            if (jsonNode.has("errcode") && jsonNode.get("errcode").asInt() != 0) {
+                throw new RuntimeException("钉钉接口错误: " + jsonNode.get("errmsg").asText());
+            }
+            return jsonNode;
+        } catch (IOException e) {
+            throw new RuntimeException("解析响应失败", e);
+        }
+    }
+}