Просмотр исходного кода

完善 OAuth2ClientServiceImplTest 单元测试

YunaiV 3 лет назад
Родитель
Сommit
b3ab1d9285
12 измененных файлов с 198 добавлено и 99 удалено
  1. 0 15
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2OpenController.http
  2. 3 51
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2OpenController.java
  3. 14 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2UserController.http
  4. 80 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2UserController.java
  5. 3 3
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/open/user/OAuth2OpenUserInfoRespVO.java
  6. 3 3
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/open/user/OAuth2OpenUserUpdateReqVO.java
  7. 0 14
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/oauth2/OAuth2OpenConvert.java
  8. 25 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/oauth2/OAuth2UserConvert.java
  9. 6 4
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2ClientServiceImpl.java
  10. 62 7
      yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/auth/OAuth2ClientServiceImplTest.java
  11. 1 1
      yudao-module-system/yudao-module-system-biz/src/test/resources/sql/create_tables.sql
  12. 1 1
      yudao-ui-admin/src/views/sso.vue

+ 0 - 15
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2OpenController.http

@@ -52,18 +52,3 @@ tenant-id: {{adminTenentId}}
 POST {{baseUrl}}/system/oauth2/check-token?token=620d307c5b4148df8a98dd6c6c547106
 Authorization: Basic ZGVmYXVsdDphZG1pbjEyMw==
 tenant-id: {{adminTenentId}}
-
-### 请求 /system/oauth2/user/get 接口 => 成功
-GET {{baseUrl}}/system/oauth2/user/get
-Authorization: Bearer 9502bd7a768a4ade920b90f41e2efd5c
-tenant-id: {{adminTenentId}}
-
-### 请求 /system/oauth2/user/update 接口 => 成功
-PUT {{baseUrl}}/system/oauth2/user/update
-Content-Type: application/json
-Authorization: Bearer 9502bd7a768a4ade920b90f41e2efd5c
-tenant-id: {{adminTenentId}}
-
-{
-  "nickname": "芋道源码"
-}

+ 3 - 51
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2OpenController.java

@@ -1,6 +1,5 @@
 package cn.iocoder.yudao.module.system.controller.admin.oauth2;
 
-import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.lang.Assert;
 import cn.hutool.core.util.ArrayUtil;
 import cn.hutool.core.util.ObjectUtil;
@@ -13,36 +12,26 @@ import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
 import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.open.OAuth2OpenAccessTokenRespVO;
 import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.open.OAuth2OpenAuthorizeInfoRespVO;
 import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.open.OAuth2OpenCheckTokenRespVO;
-import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.open.user.OAuth2OpenUserInfoRespVO;
-import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.open.user.OAuth2OpenUserUpdateReqVO;
 import cn.iocoder.yudao.module.system.convert.oauth2.OAuth2OpenConvert;
-import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
-import cn.iocoder.yudao.module.system.dal.dataobject.dept.PostDO;
 import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO;
 import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2ApproveDO;
 import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2ClientDO;
-import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
 import cn.iocoder.yudao.module.system.enums.auth.OAuth2GrantTypeEnum;
-import cn.iocoder.yudao.module.system.service.dept.DeptService;
-import cn.iocoder.yudao.module.system.service.dept.PostService;
 import cn.iocoder.yudao.module.system.service.oauth2.OAuth2ApproveService;
 import cn.iocoder.yudao.module.system.service.oauth2.OAuth2ClientService;
 import cn.iocoder.yudao.module.system.service.oauth2.OAuth2GrantService;
 import cn.iocoder.yudao.module.system.service.oauth2.OAuth2TokenService;
-import cn.iocoder.yudao.module.system.service.user.AdminUserService;
 import cn.iocoder.yudao.module.system.util.oauth2.OAuth2Utils;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiImplicitParam;
 import io.swagger.annotations.ApiImplicitParams;
 import io.swagger.annotations.ApiOperation;
 import lombok.extern.slf4j.Slf4j;
-import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
 import javax.annotation.Resource;
 import javax.servlet.http.HttpServletRequest;
-import javax.validation.Valid;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
@@ -61,7 +50,9 @@ import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUti
  * 另外,一个公司如果有多个管理后台,它们 client_id 产生的 access token 相互之间是无法互通的,即无法访问它们系统的 API 接口,直到两个 client_id 产生信任授权。
  *
  * 考虑到【本系统】暂时不想做的过于复杂,默认只有获取到 access token 之后,可以访问【本系统】管理后台的 /system-api/* 所有接口,除非手动添加 scope 控制。
- * scope 的使用示例,可见当前类的 getUserInfo 和 updateUserInfo 方法,上面有 @PreAuthorize("@ss.hasScope('user.read')") 和 @PreAuthorize("@ss.hasScope('user.write')") 注解
+ * scope 的使用示例,可见 {@link OAuth2UserController} 类
+ *
+ *
  *
  * @author 芋道源码
  */
@@ -306,43 +297,4 @@ public class OAuth2OpenController {
         return clientIdAndSecret;
     }
 
-    // ============ 用户操作的示例,展示 scope 的使用 ============
-
-    @Resource
-    private AdminUserService userService;
-    @Resource
-    private DeptService deptService;
-    @Resource
-    private PostService postService;
-
-    @GetMapping("/user/get")
-    @ApiOperation("获得用户基本信息")
-    @PreAuthorize("@ss.hasScope('user.read')")
-    public CommonResult<OAuth2OpenUserInfoRespVO> getUserInfo() {
-        // 获得用户基本信息
-        AdminUserDO user = userService.getUser(getLoginUserId());
-        OAuth2OpenUserInfoRespVO resp = OAuth2OpenConvert.INSTANCE.convert(user);
-        // 获得部门信息
-        if (user.getDeptId() != null) {
-            DeptDO dept = deptService.getDept(user.getDeptId());
-            resp.setDept(OAuth2OpenConvert.INSTANCE.convert(dept));
-        }
-        // 获得岗位信息
-        if (CollUtil.isNotEmpty(user.getPostIds())) {
-            List<PostDO> posts = postService.getPosts(user.getPostIds());
-            resp.setPosts(OAuth2OpenConvert.INSTANCE.convertList(posts));
-        }
-        return success(resp);
-    }
-
-    @PutMapping("/user/update")
-    @ApiOperation("更新用户基本信息")
-    @PreAuthorize("@ss.hasScope('user.write')")
-    public CommonResult<Boolean> updateUserInfo(@Valid @RequestBody OAuth2OpenUserUpdateReqVO reqVO) {
-        // 这里将 UserProfileUpdateReqVO =》UserProfileUpdateReqVO 对象,实现接口的复用。
-        // 主要是,AdminUserService 没有自己的 BO 对象,所以复用只能这么做
-        userService.updateUserProfile(getLoginUserId(), OAuth2OpenConvert.INSTANCE.convert(reqVO));
-        return success(true);
-    }
-
 }

+ 14 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2UserController.http

@@ -0,0 +1,14 @@
+### 请求 /system/oauth2/user/get 接口 => 成功
+GET {{baseUrl}}/system/oauth2/user/get
+Authorization: Bearer 47f9c74ec11041f193b777ebb95c3b0d
+tenant-id: {{adminTenentId}}
+
+### 请求 /system/oauth2/user/update 接口 => 成功
+PUT {{baseUrl}}/system/oauth2/user/update
+Content-Type: application/json
+Authorization: Bearer 47f9c74ec11041f193b777ebb95c3b0d
+tenant-id: {{adminTenentId}}
+
+{
+  "nickname": "芋道源码"
+}

+ 80 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2UserController.java

@@ -0,0 +1,80 @@
+package cn.iocoder.yudao.module.system.controller.admin.oauth2;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.user.OAuth2UserInfoRespVO;
+import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.user.OAuth2UserUpdateReqVO;
+import cn.iocoder.yudao.module.system.convert.oauth2.OAuth2UserConvert;
+import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
+import cn.iocoder.yudao.module.system.dal.dataobject.dept.PostDO;
+import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
+import cn.iocoder.yudao.module.system.service.dept.DeptService;
+import cn.iocoder.yudao.module.system.service.dept.PostService;
+import cn.iocoder.yudao.module.system.service.user.AdminUserService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.validation.Valid;
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
+
+/**
+ * 提供给外部应用调用为主
+ *
+ * 1. 在 getUserInfo 方法上,添加 @PreAuthorize("@ss.hasScope('user.read')") 注解,声明需要满足 scope = user.read
+ * 2. 在 updateUserInfo 方法上,添加 @PreAuthorize("@ss.hasScope('user.write')") 注解,声明需要满足 scope = user.write
+ *
+ * @author 芋道源码
+ */
+@Api(tags = "管理后台 - OAuth2.0 用户")
+@RestController
+@RequestMapping("/system/oauth2/user")
+@Validated
+@Slf4j
+public class OAuth2UserController {
+
+    @Resource
+    private AdminUserService userService;
+    @Resource
+    private DeptService deptService;
+    @Resource
+    private PostService postService;
+
+    @GetMapping("/get")
+    @ApiOperation("获得用户基本信息")
+    @PreAuthorize("@ss.hasScope('user.read')") //
+    public CommonResult<OAuth2UserInfoRespVO> getUserInfo() {
+        // 获得用户基本信息
+        AdminUserDO user = userService.getUser(getLoginUserId());
+        OAuth2UserInfoRespVO resp = OAuth2UserConvert.INSTANCE.convert(user);
+        // 获得部门信息
+        if (user.getDeptId() != null) {
+            DeptDO dept = deptService.getDept(user.getDeptId());
+            resp.setDept(OAuth2UserConvert.INSTANCE.convert(dept));
+        }
+        // 获得岗位信息
+        if (CollUtil.isNotEmpty(user.getPostIds())) {
+            List<PostDO> posts = postService.getPosts(user.getPostIds());
+            resp.setPosts(OAuth2UserConvert.INSTANCE.convertList(posts));
+        }
+        return success(resp);
+    }
+
+    @PutMapping("/update")
+    @ApiOperation("更新用户基本信息")
+    @PreAuthorize("@ss.hasScope('user.write')")
+    public CommonResult<Boolean> updateUserInfo(@Valid @RequestBody OAuth2UserUpdateReqVO reqVO) {
+        // 这里将 UserProfileUpdateReqVO =》UserProfileUpdateReqVO 对象,实现接口的复用。
+        // 主要是,AdminUserService 没有自己的 BO 对象,所以复用只能这么做
+        userService.updateUserProfile(getLoginUserId(), OAuth2UserConvert.INSTANCE.convert(reqVO));
+        return success(true);
+    }
+
+}

+ 3 - 3
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/open/user/OAuth2OpenUserInfoRespVO.java

@@ -1,4 +1,4 @@
-package cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.open.user;
+package cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.user;
 
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
@@ -8,11 +8,11 @@ import lombok.NoArgsConstructor;
 
 import java.util.List;
 
-@ApiModel("管理后台 - 【开放接口】获得用户基本信息 Response VO")
+@ApiModel("管理后台 - OAuth2.0 获得用户基本信息 Response VO")
 @Data
 @NoArgsConstructor
 @AllArgsConstructor
-public class OAuth2OpenUserInfoRespVO {
+public class OAuth2UserInfoRespVO {
 
     @ApiModelProperty(value = "用户编号", required = true, example = "1")
     private Long id;

+ 3 - 3
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/open/user/OAuth2OpenUserUpdateReqVO.java

@@ -1,4 +1,4 @@
-package cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.open.user;
+package cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.user;
 
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
@@ -10,11 +10,11 @@ import org.hibernate.validator.constraints.Length;
 import javax.validation.constraints.Email;
 import javax.validation.constraints.Size;
 
-@ApiModel("管理后台 - 【开放接口】更新用户基本信息 Request VO")
+@ApiModel("管理后台 - OAuth2.0 更新用户基本信息 Request VO")
 @Data
 @NoArgsConstructor
 @AllArgsConstructor
-public class OAuth2OpenUserUpdateReqVO {
+public class OAuth2UserUpdateReqVO {
 
     @ApiModelProperty(value = "用户昵称", required = true, example = "芋艿")
     @Size(max = 30, message = "用户昵称长度不能超过 30 个字符")

+ 0 - 14
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/oauth2/OAuth2OpenConvert.java

@@ -7,15 +7,9 @@ import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
 import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.open.OAuth2OpenAccessTokenRespVO;
 import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.open.OAuth2OpenAuthorizeInfoRespVO;
 import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.open.OAuth2OpenCheckTokenRespVO;
-import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.open.user.OAuth2OpenUserInfoRespVO;
-import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.open.user.OAuth2OpenUserUpdateReqVO;
-import cn.iocoder.yudao.module.system.controller.admin.user.vo.profile.UserProfileUpdateReqVO;
-import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
-import cn.iocoder.yudao.module.system.dal.dataobject.dept.PostDO;
 import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO;
 import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2ApproveDO;
 import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2ClientDO;
-import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
 import cn.iocoder.yudao.module.system.util.oauth2.OAuth2Utils;
 import org.mapstruct.Mapper;
 import org.mapstruct.factory.Mappers;
@@ -46,14 +40,6 @@ public interface OAuth2OpenConvert {
     }
     OAuth2OpenCheckTokenRespVO convert3(OAuth2AccessTokenDO bean);
 
-    // ============ 用户操作的示例 ============
-
-    OAuth2OpenUserInfoRespVO convert(AdminUserDO bean);
-    OAuth2OpenUserInfoRespVO.Dept convert(DeptDO dept);
-    List<OAuth2OpenUserInfoRespVO.Post> convertList(List<PostDO> list);
-
-    UserProfileUpdateReqVO convert(OAuth2OpenUserUpdateReqVO bean);
-
     default OAuth2OpenAuthorizeInfoRespVO convert(OAuth2ClientDO client, List<OAuth2ApproveDO> approves) {
         // 构建 scopes
         List<KeyValue<String, Boolean>> scopes = new ArrayList<>(client.getScopes().size());

+ 25 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/oauth2/OAuth2UserConvert.java

@@ -0,0 +1,25 @@
+package cn.iocoder.yudao.module.system.convert.oauth2;
+
+import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.user.OAuth2UserInfoRespVO;
+import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.user.OAuth2UserUpdateReqVO;
+import cn.iocoder.yudao.module.system.controller.admin.user.vo.profile.UserProfileUpdateReqVO;
+import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
+import cn.iocoder.yudao.module.system.dal.dataobject.dept.PostDO;
+import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
+import org.mapstruct.Mapper;
+import org.mapstruct.factory.Mappers;
+
+import java.util.List;
+
+@Mapper
+public interface OAuth2UserConvert {
+
+    OAuth2UserConvert INSTANCE = Mappers.getMapper(OAuth2UserConvert.class);
+
+    OAuth2UserInfoRespVO convert(AdminUserDO bean);
+    OAuth2UserInfoRespVO.Dept convert(DeptDO dept);
+    List<OAuth2UserInfoRespVO.Post> convertList(List<PostDO> list);
+
+    UserProfileUpdateReqVO convert(OAuth2UserUpdateReqVO bean);
+
+}

+ 6 - 4
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2ClientServiceImpl.java

@@ -15,6 +15,7 @@ import cn.iocoder.yudao.module.system.dal.mysql.oauth2.OAuth2ClientMapper;
 import cn.iocoder.yudao.module.system.mq.producer.auth.OAuth2ClientProducer;
 import com.google.common.annotations.VisibleForTesting;
 import lombok.Getter;
+import lombok.Setter;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Service;
@@ -51,7 +52,8 @@ public class OAuth2ClientServiceImpl implements OAuth2ClientService {
      *
      * 这里声明 volatile 修饰的原因是,每次刷新时,直接修改指向
      */
-    @Getter
+    @Getter // 解决单测
+    @Setter // 解决单测
     private volatile Map<String, OAuth2ClientDO> clientCache;
     /**
      * 缓存角色的最大更新时间,用于后续的增量轮询,判断是否有更新
@@ -151,7 +153,7 @@ public class OAuth2ClientServiceImpl implements OAuth2ClientService {
     }
 
     @VisibleForTesting
-    public void validateClientIdExists(Long id, String clientId) {
+    void validateClientIdExists(Long id, String clientId) {
         OAuth2ClientDO client = oauth2ClientMapper.selectByClientId(clientId);
         if (client == null) {
             return;
@@ -160,7 +162,7 @@ public class OAuth2ClientServiceImpl implements OAuth2ClientService {
         if (id == null) {
             throw exception(OAUTH2_CLIENT_EXISTS);
         }
-        if (!client.getClientId().equals(clientId)) {
+        if (!client.getId().equals(id)) {
             throw exception(OAUTH2_CLIENT_EXISTS);
         }
     }
@@ -189,7 +191,7 @@ public class OAuth2ClientServiceImpl implements OAuth2ClientService {
 
         // 校验客户端密钥
         if (StrUtil.isNotEmpty(clientSecret) && ObjectUtil.notEqual(client.getSecret(), clientSecret)) {
-            throw exception(OAUTH2_CLIENT_CLIENT_SECRET_ERROR, clientSecret);
+            throw exception(OAUTH2_CLIENT_CLIENT_SECRET_ERROR);
         }
         // 校验授权方式
         if (StrUtil.isNotEmpty(authorizedGrantType) && !CollUtil.contains(client.getAuthorizedGrantTypes(), authorizedGrantType)) {

+ 62 - 7
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/auth/OAuth2ClientServiceImplTest.java

@@ -1,5 +1,6 @@
-package cn.iocoder.yudao.module.system.service.auth;
+package cn.iocoder.yudao.module.system.service.oauth2;
 
+import cn.hutool.core.map.MapUtil;
 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
@@ -9,13 +10,12 @@ import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.client.OAuth2Cl
 import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2ClientDO;
 import cn.iocoder.yudao.module.system.dal.mysql.oauth2.OAuth2ClientMapper;
 import cn.iocoder.yudao.module.system.mq.producer.auth.OAuth2ClientProducer;
-import cn.iocoder.yudao.module.system.service.oauth2.OAuth2ClientServiceImpl;
-import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
 import org.springframework.boot.test.mock.mockito.MockBean;
 import org.springframework.context.annotation.Import;
 
 import javax.annotation.Resource;
+import java.util.Collections;
 import java.util.Map;
 
 import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
@@ -23,7 +23,7 @@ import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.max;
 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
-import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.OAUTH2_CLIENT_NOT_EXISTS;
+import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
 import static org.junit.jupiter.api.Assertions.*;
 import static org.mockito.Mockito.verify;
 
@@ -132,7 +132,31 @@ public class OAuth2ClientServiceImplTest extends BaseDbUnitTest {
     }
 
     @Test
-    @Disabled
+    public void testValidateClientIdExists_withId() {
+        // mock 数据
+        OAuth2ClientDO client = randomPojo(OAuth2ClientDO.class).setClientId("tudou");
+        oauth2ClientMapper.insert(client);
+        // 准备参数
+        Long id = randomLongId();
+        String clientId = "tudou";
+
+        // 调用,不会报错
+        assertServiceException(() -> oauth2ClientService.validateClientIdExists(id, clientId), OAUTH2_CLIENT_EXISTS);
+    }
+
+    @Test
+    public void testValidateClientIdExists_noId() {
+        // mock 数据
+        OAuth2ClientDO client = randomPojo(OAuth2ClientDO.class).setClientId("tudou");
+        oauth2ClientMapper.insert(client);
+        // 准备参数
+        String clientId = "tudou";
+
+        // 调用,不会报错
+        assertServiceException(() -> oauth2ClientService.validateClientIdExists(null, clientId), OAUTH2_CLIENT_EXISTS);
+    }
+
+    @Test
     public void testGetOAuth2ClientPage() {
        // mock 数据
        OAuth2ClientDO dbOAuth2Client = randomPojo(OAuth2ClientDO.class, o -> { // 等会查询到
@@ -143,10 +167,10 @@ public class OAuth2ClientServiceImplTest extends BaseDbUnitTest {
        // 测试 name 不匹配
        oauth2ClientMapper.insert(cloneIgnoreId(dbOAuth2Client, o -> o.setName("凤凰")));
        // 测试 status 不匹配
-       oauth2ClientMapper.insert(cloneIgnoreId(dbOAuth2Client, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus())));
+       oauth2ClientMapper.insert(cloneIgnoreId(dbOAuth2Client, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
        // 准备参数
        OAuth2ClientPageReqVO reqVO = new OAuth2ClientPageReqVO();
-       reqVO.setName("long");
+       reqVO.setName("");
        reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
 
        // 调用
@@ -157,4 +181,35 @@ public class OAuth2ClientServiceImplTest extends BaseDbUnitTest {
        assertPojoEquals(dbOAuth2Client, pageResult.getList().get(0));
     }
 
+    @Test
+    public void testValidOAuthClientFromCache() {
+        // mock 方法
+        OAuth2ClientDO client = randomPojo(OAuth2ClientDO.class).setClientId("default")
+                .setStatus(CommonStatusEnum.ENABLE.getStatus());
+        OAuth2ClientDO client02 = randomPojo(OAuth2ClientDO.class).setClientId("disable")
+                .setStatus(CommonStatusEnum.DISABLE.getStatus());
+        Map<String, OAuth2ClientDO> clientCache = MapUtil.<String, OAuth2ClientDO>builder()
+                .put(client.getClientId(), client)
+                .put(client02.getClientId(), client02).build();
+        oauth2ClientService.setClientCache(clientCache);
+
+        // 调用,并断言
+        assertServiceException(() -> oauth2ClientService.validOAuthClientFromCache(randomString(),
+                null, null, null, null), OAUTH2_CLIENT_NOT_EXISTS);
+        assertServiceException(() -> oauth2ClientService.validOAuthClientFromCache("disable",
+                null, null, null, null), OAUTH2_CLIENT_DISABLE);
+        assertServiceException(() -> oauth2ClientService.validOAuthClientFromCache("default",
+                randomString(), null, null, null), OAUTH2_CLIENT_CLIENT_SECRET_ERROR);
+        assertServiceException(() -> oauth2ClientService.validOAuthClientFromCache("default",
+                null, randomString(), null, null), OAUTH2_CLIENT_AUTHORIZED_GRANT_TYPE_NOT_EXISTS);
+        assertServiceException(() -> oauth2ClientService.validOAuthClientFromCache("default",
+                null, null, Collections.singleton(randomString()), null), OAUTH2_CLIENT_SCOPE_OVER);
+        assertServiceException(() -> oauth2ClientService.validOAuthClientFromCache("default",
+                null, null, null, "test"), OAUTH2_CLIENT_REDIRECT_URI_NOT_MATCH, "test");
+        // 成功调用
+        OAuth2ClientDO result = oauth2ClientService.validOAuthClientFromCache(client.getClientId(), client.getSecret(),
+                client.getAuthorizedGrantTypes().get(0), client.getScopes(), client.getRedirectUris().get(0));
+        assertPojoEquals(client, result);
+    }
+
 }

+ 1 - 1
yudao-module-system/yudao-module-system-biz/src/test/resources/sql/create_tables.sql

@@ -482,9 +482,9 @@ CREATE TABLE IF NOT EXISTS "system_oauth2_client" (
   "access_token_validity_seconds" int NOT NULL,
   "refresh_token_validity_seconds" int NOT NULL,
   "redirect_uris" varchar NOT NULL,
-  "auto_approve" bit NOT NULL DEFAULT FALSE,
   "authorized_grant_types" varchar NOT NULL,
   "scopes" varchar NOT NULL DEFAULT '',
+  "auto_approve_scopes" varchar NOT NULL DEFAULT '',
   "authorities" varchar NOT NULL DEFAULT '',
   "resource_ids" varchar NOT NULL DEFAULT '',
   "additional_information" varchar NOT NULL DEFAULT '',

+ 1 - 1
yudao-ui-admin/src/views/sso.vue

@@ -37,7 +37,7 @@
               <el-form-item style="width:100%;">
                 <el-button :loading="loading" size="medium" type="primary" style="width:60%;"
                            @click.native.prevent="handleAuthorize(true)">
-                  <span v-if="!loading">统一授权</span>
+                  <span v-if="!loading">同意授权</span>
                   <span v-else>授 权 中...</span>
                 </el-button>
                 <el-button size="medium" style="width:36%"