|
@@ -7,10 +7,7 @@ import com.management.platform.entity.DingTalkUserInfo;
|
|
|
import org.slf4j.Logger;
|
|
|
import org.slf4j.LoggerFactory;
|
|
|
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.http.*;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
import org.springframework.web.client.RestTemplate;
|
|
|
|
|
@@ -24,6 +21,7 @@ import java.util.Base64;
|
|
|
import java.util.HashMap;
|
|
|
import java.util.Map;
|
|
|
|
|
|
+
|
|
|
@Service
|
|
|
public class DingTalkService {
|
|
|
private static final Logger log = LoggerFactory.getLogger(DingTalkService.class);
|
|
@@ -41,36 +39,6 @@ public class DingTalkService {
|
|
|
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×tamp=%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);
|
|
|
- }
|
|
|
|
|
|
/**
|
|
|
* 使用临时授权码获取用户信息
|
|
@@ -81,100 +49,87 @@ public class DingTalkService {
|
|
|
try {
|
|
|
logger.info("开始获取用户OpenID,临时授权码: {}", code);
|
|
|
|
|
|
- // 1. 构造请求参数
|
|
|
- String timestamp = String.valueOf(System.currentTimeMillis());
|
|
|
- String signature = generateSignature(timestamp);
|
|
|
- logger.info("生成请求参数 - timestamp: {}, signature: {}", timestamp, signature);
|
|
|
-
|
|
|
- // 2. 构造请求体
|
|
|
- Map<String, String> requestBody = new HashMap<>();
|
|
|
- requestBody.put("tmp_auth_code", code);
|
|
|
- logger.info("构造请求体: {}", requestBody);
|
|
|
-
|
|
|
- // 3. 构造请求URL
|
|
|
- String url = String.format("%s?accessKey=%s×tamp=%s&signature=%s",
|
|
|
- GET_USER_INFO_URL, dingTalkConfig.getAppId(), timestamp, signature);
|
|
|
- logger.info("构造请求URL: {}", url);
|
|
|
-
|
|
|
- // 4. 发送请求
|
|
|
- logger.info("url===>"+url);
|
|
|
- // 2. 将 String URL 转换为不编码的 URI
|
|
|
- URI uri = new URI(url); // 关键点:直接用URI构造函数,不额外编码
|
|
|
- // 3. 发送请求(使用URI对象而非String URL)
|
|
|
- ResponseEntity<String> response = restTemplate.postForEntity(
|
|
|
- uri, // 传入URI对象而非String
|
|
|
- new HttpEntity<>(requestBody, buildHeaders()),
|
|
|
- String.class
|
|
|
- );
|
|
|
- logger.info("收到钉钉服务器响应,状态码: {}", response.getStatusCodeValue());
|
|
|
- logger.info("完整响应: {}", response.getBody());
|
|
|
-
|
|
|
- // 5. 解析响应
|
|
|
- JsonNode jsonNode = parseResponse(response.getBody());
|
|
|
- if (jsonNode == null) {
|
|
|
- throw new RuntimeException("解析响应数据失败,返回的JSON为空");
|
|
|
- }
|
|
|
-
|
|
|
- JsonNode userInfo = jsonNode.get("user_info");
|
|
|
- if (userInfo == null) {
|
|
|
- logger.info("响应中缺少user_info字段,完整响应: {}", jsonNode.toString());
|
|
|
- throw new RuntimeException("钉钉返回的用户信息不完整");
|
|
|
- }
|
|
|
-
|
|
|
- // 6. 获取用户详细信息
|
|
|
- String unionId = userInfo.get("unionid").asText();
|
|
|
- String openid = userInfo.get("openid").asText();
|
|
|
-
|
|
|
- logger.info("成功获取用户信息 - unionId: {}, openid: {}", unionId, openid);
|
|
|
- return openid;
|
|
|
+ String accessToken=getAccessToken(code);
|
|
|
+ // 2. 获取用户信息
|
|
|
+ Map<String, Object> userInfo = getUserInfo(accessToken,"me");
|
|
|
+ return userInfo.get("openId").toString();
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
logger.info("获取用户OpenID失败,临时授权码: {},错误信息: {}", code, e.getMessage(), e);
|
|
|
throw new RuntimeException("获取用户OpenID失败: " + e.getMessage(), e);
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
/**
|
|
|
- * 获取用户详细信息
|
|
|
+ * 调用 /v1.0/contact/users/{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;
|
|
|
+ private Map<String, Object> getUserInfo(String accessToken, String unionId) {
|
|
|
+ String url = "https://api.dingtalk.com/v1.0/contact/users/" + unionId;
|
|
|
+
|
|
|
+ // 设置请求头
|
|
|
+ HttpHeaders headers = new HttpHeaders();
|
|
|
+ headers.set("x-acs-dingtalk-access-token", accessToken);
|
|
|
+ headers.setContentType(MediaType.APPLICATION_JSON);
|
|
|
+
|
|
|
+ // 发送请求
|
|
|
+ ResponseEntity<Map> response = restTemplate.exchange(
|
|
|
+ url,
|
|
|
+ HttpMethod.GET,
|
|
|
+ new HttpEntity<>(headers),
|
|
|
+ Map.class
|
|
|
+ );
|
|
|
+
|
|
|
+ // 处理响应
|
|
|
+ if (!response.getStatusCode().is2xxSuccessful()) {
|
|
|
+ throw new RuntimeException("获取用户信息失败: " + response.getBody());
|
|
|
+ }
|
|
|
+
|
|
|
+ Map<String, Object> responseBody = response.getBody();
|
|
|
+ if (responseBody == null) {
|
|
|
+ throw new RuntimeException("无效的用户信息响应");
|
|
|
+ }
|
|
|
+ log.info("responseBody==>" + responseBody);
|
|
|
+
|
|
|
+ return responseBody;
|
|
|
}
|
|
|
+
|
|
|
|
|
|
/**
|
|
|
* 获取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 getAccessToken(String code) {
|
|
|
+ String url = "https://api.dingtalk.com/v1.0/oauth2/userAccessToken";
|
|
|
+ // 构建请求体
|
|
|
+ Map<String, String> requestBody = new HashMap<>();
|
|
|
+ requestBody.put("clientId", dingTalkConfig.getAppId());
|
|
|
+ requestBody.put("clientSecret", dingTalkConfig.getAppSecret());
|
|
|
+ requestBody.put("code", code);
|
|
|
+ requestBody.put("refreshToken", code);
|
|
|
+ requestBody.put("grantType", "authorization_code");
|
|
|
+
|
|
|
+ // 设置请求头
|
|
|
+ HttpHeaders headers = new HttpHeaders();
|
|
|
+ headers.setContentType(MediaType.APPLICATION_JSON);
|
|
|
+
|
|
|
+ // 发送请求
|
|
|
+ ResponseEntity<Map> response = restTemplate.exchange(
|
|
|
+ url,
|
|
|
+ HttpMethod.POST,
|
|
|
+ new HttpEntity<>(requestBody, headers),
|
|
|
+ Map.class
|
|
|
+ );
|
|
|
+ // 处理响应
|
|
|
+ if (!response.getStatusCode().is2xxSuccessful()) {
|
|
|
+ throw new RuntimeException("获取access_token失败: " + response.getBody());
|
|
|
+ }
|
|
|
+
|
|
|
+ Map<String, Object> responseBody = response.getBody();
|
|
|
+ if (responseBody == null || !responseBody.containsKey("accessToken")) {
|
|
|
+ throw new RuntimeException("无效的响应数据");
|
|
|
+ }
|
|
|
+ log.info("responseBody==>: {}", responseBody);
|
|
|
+
|
|
|
+ return responseBody.get("accessToken").toString();
|
|
|
}
|
|
|
|
|
|
/**
|