Browse Source

1、添加专有钉钉登录功能,并测试完成

fuwb 3 months ago
parent
commit
9b695b6708

+ 13 - 1
zjugis-module-system/zjugis-module-system-biz/pom.xml

@@ -156,7 +156,19 @@
             <groupId>com.zjugis.cloud</groupId>
             <artifactId>zjugis-spring-boot-starter-monitor</artifactId>
         </dependency>
-
+        <!--  浙政钉SDK      -->
+        <dependency>
+            <groupId>com.alibaba.openplatform.shared</groupId>
+            <artifactId>sdk.client</artifactId>
+            <version>2.9.0-SNAPSHOT</version>
+            <scope>system</scope>
+            <systemPath>${project.basedir}/src/main/resources/lib/zwdd-sdk-java-1.2.0.jar</systemPath>
+        </dependency>
+        <dependency>
+            <groupId>joda-time</groupId>
+            <artifactId>joda-time</artifactId>
+            <version>2.12.4</version>
+        </dependency>
     </dependencies>
     <build>
         <!-- 设置构建的 jar 包名 -->

+ 1 - 2
zjugis-module-system/zjugis-module-system-biz/src/main/java/com/zjugis/module/system/service/auth/AdminAuthServiceImpl.java

@@ -156,8 +156,7 @@ public class AdminAuthServiceImpl implements AdminAuthService {
     @Override
     public AuthLoginRespVO socialLogin(AuthSocialLoginReqVO reqVO) {
         // 使用 code 授权码,进行登录。然后,获得到绑定的用户编号
-        String userId = socialUserService.getBindUserId(UserTypeEnum.ADMIN.getValue(), reqVO.getType(),
-                reqVO.getCode(), reqVO.getState());
+        String userId = socialUserService.getBindUserId(UserTypeEnum.ADMIN.getValue(), reqVO.getType(), reqVO.getCode(), reqVO.getState());
         if (userId == null) {
             throw exception(AUTH_MOBILE_NOT_EXISTS);
         }

+ 117 - 30
zjugis-module-system/zjugis-module-system-biz/src/main/java/com/zjugis/module/system/service/social/SocialUserServiceImpl.java

@@ -2,7 +2,12 @@ package com.zjugis.module.system.service.social;
 
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.lang.Assert;
+import cn.hutool.log.Log;
+import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
+import com.alibaba.xxpt.gateway.shared.client.http.ExecutableClient;
+import com.alibaba.xxpt.gateway.shared.client.http.GetClient;
+import com.alibaba.xxpt.gateway.shared.client.http.PostClient;
 import com.xingyuv.jushauth.model.AuthCallback;
 import com.xingyuv.jushauth.model.AuthResponse;
 import com.xingyuv.jushauth.model.AuthUser;
@@ -21,8 +26,10 @@ import com.zjugis.module.system.dal.mysql.social.SocialUserMapper;
 import com.zjugis.module.system.dal.mysql.user.AdminUserMapper;
 import com.zjugis.module.system.enums.social.SocialTypeEnum;
 import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.StringUtils;
 import org.springframework.validation.annotation.Validated;
 
 import javax.annotation.Resource;
@@ -48,7 +55,6 @@ import static com.zjugis.module.system.enums.ErrorCodeConstants.SOCIAL_USER_MOBI
 @Validated
 @Slf4j
 public class SocialUserServiceImpl implements SocialUserService {
-
     @Resource// 由于自定义了 ZjugisAuthRequestFactory 无法覆盖默认的 AuthRequestFactory,所以只能注入它
     private ZjugisAuthRequestFactory zjugisAuthRequestFactory;
 
@@ -59,6 +65,12 @@ public class SocialUserServiceImpl implements SocialUserService {
     @Resource
     private AdminUserMapper adminUserMapper;
 
+    @Value("${dingding.appKey}")
+    private String appKey;
+    @Value("${dingding.appSecret}")
+    private String appSecret;
+    @Resource
+    private ExecutableClient client;
 
     @Override
     public String getAuthorizeUrl(Integer type, String redirectUri) {
@@ -73,29 +85,39 @@ public class SocialUserServiceImpl implements SocialUserService {
     public SocialUserDO authSocialUser(Integer type, String code, String state) {
         // 优先从 DB 中获取,因为 code 有且可以使用一次。
         // 在社交登录时,当未绑定 User 时,需要绑定登录,此时需要 code 使用两次
-        SocialUserDO socialUser = socialUserMapper.selectByTypeAndCodeAnState(type, code, state);
-        if (socialUser != null) {
-            return socialUser;
-        }
+//        SocialUserDO socialUser = socialUserMapper.selectByTypeAndCodeAnState(type, code, state);
+//        if (socialUser != null) {
+//            return socialUser;
+//        }
 
-        // 请求获取
-        AuthUser authUser = getAuthUser(type, code, state);
-        Assert.notNull(authUser, "三方用户不能为空");
+        // 请求获取用户信息
+//        AuthUser authUser = getAuthUser(type, code, state);
+        JSONObject accessToken = getAccessToken();
+        if (accessToken != null) {
+            String token = accessToken.getString("accessToken");
+            JSONObject userInfo = getUserInfo(token, code);
+            Assert.notNull(userInfo, "三方用户不能为空");
 
-        // 保存到 DB 中
-        socialUser = socialUserMapper.selectByTypeAndOpenid(type, authUser.getUuid());
-        if (socialUser == null) {
-            socialUser = new SocialUserDO();
-        }
-        socialUser.setType(type).setCode(code).setState(state) // 需要保存 code + state 字段,保证后续可查询
-                .setOpenid(authUser.getUuid()).setToken(authUser.getToken().getAccessToken()).setRawTokenInfo((toJsonString(authUser.getToken())))
-                .setNickname(authUser.getNickname()).setAvatar(authUser.getAvatar()).setRawUserInfo(toJsonString(authUser.getRawUserInfo()));
-        if (socialUser.getId() == null) {
-            socialUserMapper.insert(socialUser);
-        } else {
-            socialUserMapper.updateById(socialUser);
+            // 保存到 DB 中
+            SocialUserDO socialUser = socialUserMapper.selectByTypeAndOpenid(type, userInfo.getLong("accountId").toString());
+            if (socialUser == null) {
+                socialUser = new SocialUserDO();
+                socialUser.setType(type)
+                        .setState(state)
+                        .setOpenid(userInfo.getString("accountId"))
+                        .setToken(token)
+                        .setRawTokenInfo(toJsonString(accessToken))
+                        .setNickname(userInfo.getString("nickNameCn"))
+                        .setRawUserInfo(toJsonString(userInfo));
+            }
+            if (socialUser.getId() == null) {
+                socialUserMapper.insert(socialUser);
+            } else {
+                socialUserMapper.updateById(socialUser);
+            }
+            return socialUser;
         }
-        return socialUser;
+        return null;
     }
 
     @Override
@@ -152,28 +174,47 @@ public class SocialUserServiceImpl implements SocialUserService {
         String userId;
 
         // 如果未绑定的社交用户,进行自动绑定
-        SocialUserBindDO socialUserBind = socialUserBindMapper.selectByUserTypeAndSocialUserId(userType,
-                socialUser.getId());
+        SocialUserBindDO socialUserBind = socialUserBindMapper.selectByUserTypeAndSocialUserId(userType, socialUser.getId());
         if (socialUserBind == null) {
             String rawUserInfo = socialUser.getRawUserInfo();
-            String mobile = JSONObject.parseObject(rawUserInfo).get("mobile").toString();
-            Object avatarUrl = JSONObject.parseObject(rawUserInfo).get("avatarUrl");
+            JSONObject jsonObject = JSONObject.parseObject(rawUserInfo);
+            // todo 手机号绑定未完成
+            String mobile = jsonObject.getString("account");
+            String accountId = jsonObject.getLong("accountId").toString();
+//            Object avatarUrl = JSONObject.parseObject(rawUserInfo).get("avatarUrl");
             AdminUserDO user = adminUserMapper.selectByMobile(mobile);
             if(user == null){
                 throw exception(SOCIAL_USER_MOBILE_NOT_FOUND);
             }
-            bindSocialUser(new SocialUserBindReqDTO(user.getId(), userType,
-                    type, code, state));
+//            bindSocialUser(new SocialUserBindReqDTO(user.getId(), userType, type, code, state));
+            bindSocialUser(user.getId(), userType, type, accountId);
             userId = user.getId();
-            if (avatarUrl != null) {
-                adminUserMapper.updateById(new AdminUserDO().setId(userId).setAvatar(avatarUrl.toString()));
-            }
+//            if (avatarUrl != null) {
+//                adminUserMapper.updateById(new AdminUserDO().setId(userId).setAvatar(avatarUrl.toString()));
+//            }
         } else {
             userId = socialUserBind.getUserId();
         }
         return userId;
     }
 
+    /**
+     * 绑定社交用户
+     *
+     * @param userId
+     * @param userType
+     * @param type
+     * @param accountId
+     */
+    private void bindSocialUser(String userId, Integer userType, Integer type, String accountId) {
+        SocialUserDO socialUser = socialUserMapper.selectByTypeAndOpenid(type, accountId);
+        // 绑定当前登录的社交用户
+        SocialUserBindDO socialUserBind = SocialUserBindDO.builder()
+                .userId(userId).userType(userType)
+                .socialUserId(socialUser.getId()).socialType(socialUser.getType()).build();
+        socialUserBindMapper.insert(socialUserBind);
+    }
+
     @Override
     public List<String> getBindUserIds(Collection<String> socialIds, Integer socialType) {
         List<SocialUserBindDO> socialUserList = socialUserBindMapper.selectListBySocialIds(socialIds,
@@ -218,4 +259,50 @@ public class SocialUserServiceImpl implements SocialUserService {
         return (AuthUser) authResponse.getData();
     }
 
+    public JSONObject getUserInfo(String accessToken, String authCode) {
+        if (StringUtils.hasLength(accessToken)) {
+            PostClient postClient = client.newPostClient("/rpc/oauth2/getuserinfo_bycode.json");
+            postClient.addParameter("access_token", accessToken);
+            postClient.addParameter("code", authCode);
+            String post = postClient.post();
+            JSONObject jsonObject = JSON.parseObject(post);
+//            log.info("UserInfo :[{}]", jsonObject);
+            Boolean aBoolean = jsonObject.getBoolean("success");
+            if (aBoolean) {
+                JSONObject content = jsonObject.getJSONObject("content");
+                Boolean success = content.getBoolean("success");
+                if (success) {
+                    return content.getJSONObject("data");
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 获取专有钉钉AccessToken
+     *
+     * @return
+     */
+    private JSONObject getAccessToken() {
+        String api = "/gettoken.json";
+        GetClient getClient = client.newGetClient(api);
+        //设置参数
+        getClient.addParameter("appkey", appKey);
+        getClient.addParameter("appsecret", appSecret);
+        //调用API
+        String apiResult = getClient.get();
+        JSONObject jsonObject = JSONObject.parseObject(apiResult);
+        Boolean aBoolean = jsonObject.getBoolean("success");
+        Log.get().info("用户钉钉信息:{}", jsonObject);
+        if (aBoolean) {
+            JSONObject content = jsonObject.getJSONObject("content");
+            Boolean success = content.getBoolean("success");
+            if (success) {
+                return content.getJSONObject("data");
+            }
+        }
+        return null;
+    }
+
 }

+ 39 - 0
zjugis-module-system/zjugis-module-system-biz/src/main/java/com/zjugis/module/system/util/ExecutableClientConfig.java

@@ -0,0 +1,39 @@
+package com.zjugis.module.system.util;
+
+import com.alibaba.xxpt.gateway.shared.client.http.ExecutableClient;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author: Fuwb
+ * @date: 2025/3/28
+ * @time: 9:24
+ * @description:
+ */
+@Component
+public class ExecutableClientConfig {
+    @Value("${dingding.appKey}")
+    private String appKey;
+
+    @Value("${dingding.appSecret}")
+    private String appSecret;
+
+    @Value("${dingding.domainName}")
+    private String domainName;
+
+    @Bean
+    public ExecutableClient executableClient() {
+        ExecutableClient instance = ExecutableClient.getInstance();
+        instance.setDomainName(domainName);
+        instance.setProtocal("https");
+        //应用App Key
+        instance.setAccessKey(appKey);
+        //应用App Secret
+        instance.setSecretKey(appSecret);
+        instance.init();
+        return instance;
+    }
+
+
+}

+ 9 - 2
zjugis-module-system/zjugis-module-system-biz/src/main/resources/application-dev.yaml

@@ -173,8 +173,10 @@ justauth:
   enabled: true
   type:
     DINGTALK: # 钉钉
-      client-id: dingk0ggukejc4xacgku
-      client-secret: 1Irqm3obWLCWTokhrCgbrcMIX7klSI3s_ljiBZrAzMfnpttJTUJHIBCi8C-2rD2O
+#      client-id: dingk0ggukejc4xacgku
+      client-id: ruian_oa_test_dingoa
+#      client-secret: 1Irqm3obWLCWTokhrCgbrcMIX7klSI3s_ljiBZrAzMfnpttJTUJHIBCi8C-2rD2O
+      client-secret: 7BJ74Ke76e8lil84oZzd7gV9zX3zild3DBWxYj7u
       ignore-check-redirect-uri: true
     WECHAT_ENTERPRISE: # 企业微信
       client-id: wwd411c69a39ad2e54
@@ -192,3 +194,8 @@ deptId:
 roleId:
   bj: 3000021
   normal: 2
+
+dingding:
+  appKey: ruian_oa_test_dingoa-7vhnQzQzi
+  appSecret: 7BJ74Ke76e8lil84oZzd7gV9zX3zild3DBWxYj7u
+  domainName: open.on-premises.dingtalk.com

BIN
zjugis-module-system/zjugis-module-system-biz/src/main/resources/lib/zwdd-sdk-java-1.2.0.jar