Commit ea5fd5d9034685196f68f7da875308cdc329d99c

Authored by YunaiV
1 parent 8aed362e

feat(system): 升级钉钉 V2 社交登录并校验用户标识

yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/enums/social/SocialTypeEnum.java
... ... @@ -25,9 +25,11 @@ public enum SocialTypeEnum implements ArrayValuable<Integer> {
25 25 /**
26 26 * 钉钉
27 27 *
28   - * @see <a href="https://developers.dingtalk.com/document/app/obtain-identity-credentials">接入文档</a>
  28 + * 使用新版登录,对应 JustAuth 的 DINGTALK_V2,相关反馈:https://t.zsxq.com/QY7xI
  29 + *
  30 + * @see <a href="https://open.dingtalk.com/document/app/obtain-identity-credentials">接入文档</a>
29 31 */
30   - DINGTALK(20, "DINGTALK"),
  32 + DINGTALK(20, "DINGTALK_V2"),
31 33  
32 34 /**
33 35 * 企业微信
... ...
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialClientServiceImpl.java
... ... @@ -16,6 +16,7 @@ import cn.hutool.core.thread.ThreadUtil;
16 16 import cn.hutool.core.util.DesensitizedUtil;
17 17 import cn.hutool.core.util.ObjUtil;
18 18 import cn.hutool.core.util.ReflectUtil;
  19 +import cn.hutool.core.util.StrUtil;
19 20 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
20 21 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
21 22 import cn.iocoder.yudao.framework.common.pojo.PageResult;
... ... @@ -187,7 +188,12 @@ public class SocialClientServiceImpl implements SocialClientService {
187 188 if (!authResponse.ok()) {
188 189 throw exception(SOCIAL_USER_AUTH_FAILURE, authResponse.getMsg());
189 190 }
190   - return (AuthUser) authResponse.getData();
  191 + // 部分平台获取用户信息失败时,仍然返回成功,但没有用户标识。例如说,钉钉新版登录缺少权限时,接口返回 403,但 JustAuth 不校验
  192 + AuthUser authUser = (AuthUser) authResponse.getData();
  193 + if (authUser == null || StrUtil.isBlank(authUser.getUuid())) {
  194 + throw exception(SOCIAL_USER_AUTH_FAILURE, "未获取到用户标识");
  195 + }
  196 + return authUser;
191 197 }
192 198  
193 199 /**
... ...
yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/social/SocialClientServiceImplTest.java
... ... @@ -146,6 +146,48 @@ public class SocialClientServiceImplTest extends BaseDbUnitTest {
146 146 }
147 147  
148 148 @Test
  149 + public void testAuthSocialUser_uuidNull() {
  150 + // 准备参数
  151 + Integer socialType = SocialTypeEnum.DINGTALK.getType();
  152 + Integer userType = randomPojo(UserTypeEnum.class).getValue();
  153 + String code = randomString();
  154 + String state = randomString();
  155 + // mock 方法(AuthRequest)
  156 + AuthRequest authRequest = mock(AuthRequest.class);
  157 + when(authRequestFactory.get(eq("DINGTALK_V2"))).thenReturn(authRequest);
  158 + // mock 方法(AuthResponse):获取用户信息失败时,JustAuth 仍然返回成功,但 uuid 为空
  159 + AuthUser authUser = randomPojo(AuthUser.class, o -> o.setUuid(null));
  160 + AuthResponse<AuthUser> authResponse = new AuthResponse<>(2000, null, authUser);
  161 + when(authRequest.login(any())).thenReturn(authResponse);
  162 +
  163 + // 调用并断言
  164 + assertServiceException(
  165 + () -> socialClientService.getAuthUser(socialType, userType, code, state),
  166 + SOCIAL_USER_AUTH_FAILURE, "未获取到用户标识");
  167 + }
  168 +
  169 + @Test
  170 + public void testAuthSocialUser_uuidBlank() {
  171 + // 准备参数
  172 + Integer socialType = SocialTypeEnum.DINGTALK.getType();
  173 + Integer userType = randomPojo(UserTypeEnum.class).getValue();
  174 + String code = randomString();
  175 + String state = randomString();
  176 + // mock 方法(AuthRequest)
  177 + AuthRequest authRequest = mock(AuthRequest.class);
  178 + when(authRequestFactory.get(eq("DINGTALK_V2"))).thenReturn(authRequest);
  179 + // mock 方法(AuthResponse)
  180 + AuthUser authUser = randomPojo(AuthUser.class, o -> o.setUuid(" "));
  181 + AuthResponse<AuthUser> authResponse = new AuthResponse<>(2000, null, authUser);
  182 + when(authRequest.login(any())).thenReturn(authResponse);
  183 +
  184 + // 调用并断言
  185 + assertServiceException(
  186 + () -> socialClientService.getAuthUser(socialType, userType, code, state),
  187 + SOCIAL_USER_AUTH_FAILURE, "未获取到用户标识");
  188 + }
  189 +
  190 + @Test
149 191 public void testBuildAuthRequest_clientNull() {
150 192 // 准备参数
151 193 Integer socialType = SocialTypeEnum.WECHAT_MP.getType();
... ...
yudao-server/src/main/resources/application-dev.yaml
... ... @@ -181,7 +181,7 @@ yudao:
181 181 justauth:
182 182 enabled: true
183 183 type:
184   - DINGTALK: # 钉钉
  184 + DINGTALK_V2: # 钉钉(新版登录)
185 185 client-id: dingvrnreaje3yqvzhxg
186 186 client-secret: i8E6iZyDvZj51JIb0tYsYfVQYOks9Cq1lgryEjFRqC79P3iJcrxEwT6Qk2QvLrLI
187 187 ignore-check-redirect-uri: true
... ...
yudao-server/src/main/resources/application-local.yaml
... ... @@ -254,7 +254,7 @@ yudao:
254 254 justauth:
255 255 enabled: true
256 256 type:
257   - DINGTALK: # 钉钉
  257 + DINGTALK_V2: # 钉钉(新版登录)
258 258 client-id: dingvrnreaje3yqvzhxg
259 259 client-secret: i8E6iZyDvZj51JIb0tYsYfVQYOks9Cq1lgryEjFRqC79P3iJcrxEwT6Qk2QvLrLI
260 260 ignore-check-redirect-uri: true
... ...