完善 OAuth2ClientServiceImplTest 单元测试

This commit is contained in:
YunaiV 2022-05-24 10:13:05 +08:00
parent 668551350f
commit b3ab1d9285
12 changed files with 198 additions and 99 deletions

View File

@ -52,18 +52,3 @@ tenant-id: {{adminTenentId}}
POST {{baseUrl}}/system/oauth2/check-token?token=620d307c5b4148df8a98dd6c6c547106 POST {{baseUrl}}/system/oauth2/check-token?token=620d307c5b4148df8a98dd6c6c547106
Authorization: Basic ZGVmYXVsdDphZG1pbjEyMw== Authorization: Basic ZGVmYXVsdDphZG1pbjEyMw==
tenant-id: {{adminTenentId}} 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": "芋道源码"
}

View File

@ -1,6 +1,5 @@
package cn.iocoder.yudao.module.system.controller.admin.oauth2; 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.lang.Assert;
import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil; 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.OAuth2OpenAccessTokenRespVO;
import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.open.OAuth2OpenAuthorizeInfoRespVO; 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.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.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.OAuth2AccessTokenDO;
import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2ApproveDO; 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.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.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.OAuth2ApproveService;
import cn.iocoder.yudao.module.system.service.oauth2.OAuth2ClientService; 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.OAuth2GrantService;
import cn.iocoder.yudao.module.system.service.oauth2.OAuth2TokenService; 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 cn.iocoder.yudao.module.system.util.oauth2.OAuth2Utils;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams; import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; 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 产生信任授权 * 另外一个公司如果有多个管理后台它们 client_id 产生的 access token 相互之间是无法互通的即无法访问它们系统的 API 接口直到两个 client_id 产生信任授权
* *
* 考虑到本系统暂时不想做的过于复杂默认只有获取到 access token 之后可以访问本系统管理后台的 /system-api/* 所有接口除非手动添加 scope 控制 * 考虑到本系统暂时不想做的过于复杂默认只有获取到 access token 之后可以访问本系统管理后台的 /system-api/* 所有接口除非手动添加 scope 控制
* scope 的使用示例可见当前类的 getUserInfo updateUserInfo 方法上面有 @PreAuthorize("@ss.hasScope('user.read')") @PreAuthorize("@ss.hasScope('user.write')") 注解 * scope 的使用示例可见 {@link OAuth2UserController}
*
*
* *
* @author 芋道源码 * @author 芋道源码
*/ */
@ -306,43 +297,4 @@ public class OAuth2OpenController {
return clientIdAndSecret; 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);
}
} }

View File

@ -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": "芋道源码"
}

View File

@ -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);
}
}

View File

@ -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.ApiModel;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
@ -8,11 +8,11 @@ import lombok.NoArgsConstructor;
import java.util.List; import java.util.List;
@ApiModel("管理后台 - 【开放接口】获得用户基本信息 Response VO") @ApiModel("管理后台 - OAuth2.0 获得用户基本信息 Response VO")
@Data @Data
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
public class OAuth2OpenUserInfoRespVO { public class OAuth2UserInfoRespVO {
@ApiModelProperty(value = "用户编号", required = true, example = "1") @ApiModelProperty(value = "用户编号", required = true, example = "1")
private Long id; private Long id;

View File

@ -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.ApiModel;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
@ -10,11 +10,11 @@ import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.Email; import javax.validation.constraints.Email;
import javax.validation.constraints.Size; import javax.validation.constraints.Size;
@ApiModel("管理后台 - 【开放接口】更新用户基本信息 Request VO") @ApiModel("管理后台 - OAuth2.0 更新用户基本信息 Request VO")
@Data @Data
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
public class OAuth2OpenUserUpdateReqVO { public class OAuth2UserUpdateReqVO {
@ApiModelProperty(value = "用户昵称", required = true, example = "芋艿") @ApiModelProperty(value = "用户昵称", required = true, example = "芋艿")
@Size(max = 30, message = "用户昵称长度不能超过 30 个字符") @Size(max = 30, message = "用户昵称长度不能超过 30 个字符")

View File

@ -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.OAuth2OpenAccessTokenRespVO;
import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.open.OAuth2OpenAuthorizeInfoRespVO; 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.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.OAuth2AccessTokenDO;
import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2ApproveDO; 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.oauth2.OAuth2ClientDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.util.oauth2.OAuth2Utils; import cn.iocoder.yudao.module.system.util.oauth2.OAuth2Utils;
import org.mapstruct.Mapper; import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers; import org.mapstruct.factory.Mappers;
@ -46,14 +40,6 @@ public interface OAuth2OpenConvert {
} }
OAuth2OpenCheckTokenRespVO convert3(OAuth2AccessTokenDO bean); 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) { default OAuth2OpenAuthorizeInfoRespVO convert(OAuth2ClientDO client, List<OAuth2ApproveDO> approves) {
// 构建 scopes // 构建 scopes
List<KeyValue<String, Boolean>> scopes = new ArrayList<>(client.getScopes().size()); List<KeyValue<String, Boolean>> scopes = new ArrayList<>(client.getScopes().size());

View File

@ -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);
}

View File

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

View File

@ -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.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; 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.dataobject.oauth2.OAuth2ClientDO;
import cn.iocoder.yudao.module.system.dal.mysql.oauth2.OAuth2ClientMapper; 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.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.junit.jupiter.api.Test;
import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.Collections;
import java.util.Map; import java.util.Map;
import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; 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.assertPojoEquals;
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; 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.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.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
@ -132,7 +132,31 @@ public class OAuth2ClientServiceImplTest extends BaseDbUnitTest {
} }
@Test @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() { public void testGetOAuth2ClientPage() {
// mock 数据 // mock 数据
OAuth2ClientDO dbOAuth2Client = randomPojo(OAuth2ClientDO.class, o -> { // 等会查询到 OAuth2ClientDO dbOAuth2Client = randomPojo(OAuth2ClientDO.class, o -> { // 等会查询到
@ -143,10 +167,10 @@ public class OAuth2ClientServiceImplTest extends BaseDbUnitTest {
// 测试 name 不匹配 // 测试 name 不匹配
oauth2ClientMapper.insert(cloneIgnoreId(dbOAuth2Client, o -> o.setName("凤凰"))); oauth2ClientMapper.insert(cloneIgnoreId(dbOAuth2Client, o -> o.setName("凤凰")));
// 测试 status 不匹配 // 测试 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(); OAuth2ClientPageReqVO reqVO = new OAuth2ClientPageReqVO();
reqVO.setName("long"); reqVO.setName("");
reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
// 调用 // 调用
@ -157,4 +181,35 @@ public class OAuth2ClientServiceImplTest extends BaseDbUnitTest {
assertPojoEquals(dbOAuth2Client, pageResult.getList().get(0)); 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);
}
} }

View File

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

View File

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