From c66f3ca48216decddb32a7ad3fdde6bdfe1c055c Mon Sep 17 00:00:00 2001 From: Jay <csj123456> Date: 星期三, 16 十月 2024 15:31:09 +0800 Subject: [PATCH] Merge remote-tracking branch 'origin/master' --- iailab-module-infra/iailab-module-infra-biz/src/main/java/com/iailab/module/infra/controller/admin/actuator/ActuatorController.java | 92 ++++ iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/permission/PermissionController.java | 16 iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/permission/MenuService.java | 15 iailab-module-system/iailab-module-system-biz/src/test/java/com/iailab/module/system/controller/admin/oauth2/OAuth2OpenControllerTest.java | 674 ++++++++++++++++---------------- iailab-framework/iailab-common-security/src/main/java/com/iailab/framework/security/core/LoginUser.java | 4 iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/convert/auth/AuthConvert.java | 1 iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/oauth2/OAuth2OpenController.java | 28 iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/permission/MenuServiceImpl.java | 59 ++ iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/permission/PermissionService.java | 2 iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/app/AppServiceImpl.java | 105 ++-- iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/permission/PermissionServiceImpl.java | 60 +- iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/auth/AuthController.java | 88 +++ iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/oauth2/vo/open/OAuth2OpenLoginReqVO.java | 6 iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/app/AppController.java | 17 iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/app/AppService.java | 6 iailab-module-system/iailab-module-system-api/src/main/java/com/iailab/module/system/api/oauth2/OAuth2TokenApi.java | 2 16 files changed, 716 insertions(+), 459 deletions(-) diff --git a/iailab-framework/iailab-common-security/src/main/java/com/iailab/framework/security/core/LoginUser.java b/iailab-framework/iailab-common-security/src/main/java/com/iailab/framework/security/core/LoginUser.java index fe0cce1..989ef9a 100644 --- a/iailab-framework/iailab-common-security/src/main/java/com/iailab/framework/security/core/LoginUser.java +++ b/iailab-framework/iailab-common-security/src/main/java/com/iailab/framework/security/core/LoginUser.java @@ -47,6 +47,10 @@ * 过期时间 */ private LocalDateTime expiresTime; + /** + * 访问令牌 + */ + private String accessToken; // ========== 上下文 ========== /** diff --git a/iailab-module-infra/iailab-module-infra-biz/src/main/java/com/iailab/module/infra/controller/admin/actuator/ActuatorController.java b/iailab-module-infra/iailab-module-infra-biz/src/main/java/com/iailab/module/infra/controller/admin/actuator/ActuatorController.java new file mode 100644 index 0000000..3fdf6e7 --- /dev/null +++ b/iailab-module-infra/iailab-module-infra-biz/src/main/java/com/iailab/module/infra/controller/admin/actuator/ActuatorController.java @@ -0,0 +1,92 @@ +package com.iailab.module.infra.controller.admin.actuator; + +import cn.hutool.core.util.NumberUtil; +import com.alibaba.fastjson.JSONObject; +import com.iailab.framework.common.pojo.CommonResult; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.swing.filechooser.FileSystemView; +import java.io.File; +import java.lang.management.ManagementFactory; +import java.lang.management.OperatingSystemMXBean; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @Description: 硬盘内存监控等 + * @author: iailab + */ +@Slf4j +@RestController +@RequestMapping("/infra/actuator") +public class ActuatorController { + + + /** + * 内存详情 + * @return + * @throws Exception + */ + @GetMapping("/memory/info") + public CommonResult<?> getRedisInfo() throws Exception { + OperatingSystemMXBean operatingSystemMXBean = ManagementFactory.getOperatingSystemMXBean(); + JSONObject operatingSystemJson = JSONObject.parseObject(JSONObject.toJSONString(operatingSystemMXBean)); + long totalPhysicalMemory = operatingSystemJson.getLongValue("totalPhysicalMemorySize"); + long freePhysicalMemory = operatingSystemJson.getLongValue("freePhysicalMemorySize"); + long usedPhysicalMemory = totalPhysicalMemory - freePhysicalMemory; + Runtime runtime = Runtime.getRuntime(); + Map<String,Number> result = new HashMap<>(); + result.put("memory.physical.total", totalPhysicalMemory); + result.put("memory.physical.used", freePhysicalMemory); + result.put("memory.physical.free", usedPhysicalMemory); + result.put("memory.physical.usage", NumberUtil.div(usedPhysicalMemory, totalPhysicalMemory)); + result.put("memory.runtime.total", runtime.totalMemory()); + result.put("memory.runtime.used", runtime.freeMemory()); + result.put("memory.runtime.max", runtime.totalMemory() - runtime.freeMemory()); + result.put("memory.runtime.free", runtime.maxMemory() - runtime.totalMemory() + runtime.freeMemory()); + result.put("memory.runtime.usage", NumberUtil.div(runtime.totalMemory() - runtime.freeMemory(), runtime.totalMemory())); + return CommonResult.success(result); + } + + /** + * @功能:获取磁盘信息 + * @return + */ + @GetMapping("/disk/info") + public CommonResult<List<Map<String,Object>>> queryDiskInfo(){ + CommonResult<List<Map<String,Object>>> res = new CommonResult<>(); + try { + // 当前文件系统类 + FileSystemView fsv = FileSystemView.getFileSystemView(); + // 列出所有windows 磁盘 + File[] fs = File.listRoots(); + log.info("查询磁盘信息:"+fs.length+"个"); + List<Map<String,Object>> list = new ArrayList<>(); + for (int i = 0; i < fs.length; i++) { + if(fs[i].getTotalSpace()==0) { + continue; + } + Map<String,Object> map = new HashMap(5); + map.put("name", fsv.getSystemDisplayName(fs[i])); + map.put("max", fs[i].getTotalSpace()); + map.put("rest", fs[i].getFreeSpace()); + map.put("restPPT", (fs[i].getTotalSpace()-fs[i].getFreeSpace())*100/fs[i].getTotalSpace()); + list.add(map); + log.info(map.toString()); + } + res.setData(list); + res.success("查询成功"); + } catch (Exception e) { + res.setMsg("查询失败"+e.getMessage()); + } + return res; + } + +} diff --git a/iailab-module-system/iailab-module-system-api/src/main/java/com/iailab/module/system/api/oauth2/OAuth2TokenApi.java b/iailab-module-system/iailab-module-system-api/src/main/java/com/iailab/module/system/api/oauth2/OAuth2TokenApi.java index 8a96b1c..8105e0f 100644 --- a/iailab-module-system/iailab-module-system-api/src/main/java/com/iailab/module/system/api/oauth2/OAuth2TokenApi.java +++ b/iailab-module-system/iailab-module-system-api/src/main/java/com/iailab/module/system/api/oauth2/OAuth2TokenApi.java @@ -44,7 +44,7 @@ @Operation(summary = "刷新访问令牌") @Parameters({ @Parameter(name = "refreshToken", description = "刷新令牌", required = true, example = "haha"), - @Parameter(name = "clientId", description = "客户端编号", required = true, example = "iailabyuanma") + @Parameter(name = "clientId", description = "客户端编号", required = true, example = "iailab") }) CommonResult<OAuth2AccessTokenRespDTO> refreshAccessToken(@RequestParam("refreshToken") String refreshToken, @RequestParam("clientId") String clientId); diff --git a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/app/AppController.java b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/app/AppController.java index 5438a35..08d9c28 100644 --- a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/app/AppController.java +++ b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/app/AppController.java @@ -10,6 +10,7 @@ import com.iailab.module.system.controller.admin.app.vo.AppPageReqVO; import com.iailab.module.system.controller.admin.app.vo.AppRespVO; import com.iailab.module.system.controller.admin.app.vo.AppSaveReqVO; +import com.iailab.module.system.controller.admin.auth.vo.AuthPermissionInfoRespVO; import com.iailab.module.system.dal.dataobject.app.AppDO; import com.iailab.module.system.service.app.AppService; import io.swagger.v3.oas.annotations.Operation; @@ -85,14 +86,14 @@ return success(BeanUtils.toBean(appDOS, AppRespVO.class)); } -// @GetMapping("/getAppMenu") -// @Operation(summary = "获得应用菜单列表") -// @PreAuthorize("@ss.hasPermission('system:app-menu:query')") -// @Parameter(name = "id", description = "ID", required = true, example = "1024") -// public CommonResult<List<AppRespVO>> getAppMenu(@RequestParam("id") Long id) { -// List<AppMenuRespDTO> appDOS = appService.getAppMenu(id); -// return success(BeanUtils.toBean(appDOS, AppRespVO.class)); -// } + @GetMapping("/getAppMenu") + @Operation(summary = "获得应用菜单列表") + @PreAuthorize("@ss.hasPermission('system:app-menu:query')") + @Parameter(name = "id", description = "ID", required = true, example = "1024") + public CommonResult<List<AppRespVO>> getAppMenu(@RequestParam("id") Long id) { + List<AuthPermissionInfoRespVO.MenuVO> appDOS = appService.getAppMenu(id); + return success(BeanUtils.toBean(appDOS, AppRespVO.class)); + } @GetMapping("/export-excel") @Operation(summary = "导出租户 Excel") diff --git a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/auth/AuthController.java b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/auth/AuthController.java index 1637ed5..ef22778 100644 --- a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/auth/AuthController.java +++ b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/auth/AuthController.java @@ -5,16 +5,21 @@ import com.iailab.framework.common.enums.CommonStatusEnum; import com.iailab.framework.common.enums.UserTypeEnum; import com.iailab.framework.common.pojo.CommonResult; +import com.iailab.framework.common.util.object.BeanUtils; import com.iailab.framework.security.config.SecurityProperties; import com.iailab.framework.security.core.util.SecurityFrameworkUtils; +import com.iailab.module.system.controller.admin.app.vo.AppMenuRespVO; +import com.iailab.module.system.controller.admin.app.vo.AppRespVO; import com.iailab.module.system.controller.admin.auth.vo.*; import com.iailab.module.system.controller.admin.permission.vo.menu.MenuListReqVO; +import com.iailab.module.system.controller.admin.permission.vo.menu.MenuRespVO; import com.iailab.module.system.convert.auth.AuthConvert; import com.iailab.module.system.dal.dataobject.app.AppDO; import com.iailab.module.system.dal.dataobject.permission.MenuDO; import com.iailab.module.system.dal.dataobject.permission.RoleDO; import com.iailab.module.system.dal.dataobject.user.AdminUserDO; import com.iailab.module.system.enums.logger.LoginLogTypeEnum; +import com.iailab.module.system.enums.permission.MenuTypeEnum; import com.iailab.module.system.service.app.AppService; import com.iailab.module.system.service.auth.AdminAuthService; import com.iailab.module.system.service.permission.MenuService; @@ -34,9 +39,8 @@ import javax.annotation.security.PermitAll; import javax.servlet.http.HttpServletRequest; import javax.validation.Valid; -import java.util.Collections; -import java.util.List; -import java.util.Set; +import java.util.*; +import java.util.stream.Collectors; import static com.iailab.framework.common.pojo.CommonResult.success; import static com.iailab.framework.common.util.collection.CollectionUtils.convertSet; @@ -121,32 +125,94 @@ return success(AuthConvert.INSTANCE.convert(user, roles, menuList)); } - @GetMapping("/get-app-permission-info") + @GetMapping("/get-app-permission") @Operation(summary = "获取登录用户的app权限信息") - public CommonResult<AuthPermissionInfoRespVO> getAppPermissionInfo() { + public CommonResult<List<AppRespVO>> getAppPermission() { + List<AppRespVO> appList = new ArrayList<>(); // 1.1 获得用户信息 AdminUserDO user = userService.getUser(getLoginUserId()); if (user == null) { return success(null); } - // 1.2 获得角色列表 Set<Long> roleIds = permissionService.getUserRoleIdListByUserId(getLoginUserId()); if (CollUtil.isEmpty(roleIds)) { - return success(AuthConvert.INSTANCE.convert(user, Collections.emptyList(), Collections.emptyList())); + return success(appList); } List<RoleDO> roles = roleService.getRoleList(roleIds); roles.removeIf(role -> !CommonStatusEnum.ENABLE.getStatus().equals(role.getStatus())); // 移除禁用的角色 // 1.3 获得应用菜单列表 - MenuListReqVO reqVO = new MenuListReqVO(); - List<MenuDO> appMenuList = menuService.getAppMenuList(reqVO); Set<Long> menuIds = permissionService.getRoleMenuListByRoleId(convertSet(roles, RoleDO::getId)); List<MenuDO> menuList = menuService.getMenuList(menuIds); - menuList.retainAll(appMenuList); + //只要一级菜单,一级菜单即是应用 + menuList = menuList.stream().filter(menu -> menu.getParentId() == 0l).collect(Collectors.toList()); menuList = menuService.filterDisableMenus(menuList); + List<Long> ids = menuList.stream().map(MenuDO::getAppId).collect(Collectors.toList()); + List<AppDO> appDOS = appService.selectBatchIds(ids); + //排序 + Collections.sort(appDOS, Comparator.comparing(AppDO::getOrderNum)); // 2. 拼接结果返回 - return success(AuthConvert.INSTANCE.convertAppMenu(user, roles, menuList)); + return success(BeanUtils.toBean(appDOS, AppRespVO.class)); + } + + @GetMapping("/get-app-menu-permission") + @Operation(summary = "获取登录用户的app权限信息") + public CommonResult<List<AuthPermissionInfoRespVO.MenuVO>> getAppMenuPermission(@RequestParam("id") Long id) { + List<AuthPermissionInfoRespVO.MenuVO> menuVOS = new ArrayList<>(); + // 1.1 获得用户信息 + AdminUserDO user = userService.getUser(getLoginUserId()); + if (user == null) { + return success(null); + } + // 1.2 获得角色列表 + Set<Long> roleIds = permissionService.getUserRoleIdListByUserId(getLoginUserId()); + if (CollUtil.isEmpty(roleIds)) { + return success(menuVOS); + } + List<RoleDO> roles = roleService.getRoleList(roleIds); + roles.removeIf(role -> !CommonStatusEnum.ENABLE.getStatus().equals(role.getStatus())); // 移除禁用的角色 + + // 1.3 获得应用菜单列表 + Set<Long> menuIds = permissionService.getRoleMenuListByRoleId(convertSet(roles, RoleDO::getId)); + List<MenuDO> menuList = menuService.getMenuList(menuIds); + menuList = menuService.filterDisableMenus(menuList); + MenuDO menuDO = menuService.getMenuByAppId(id); + List<MenuDO> children = new LinkedList<>(); + // 遍历每一层 + Collection<Long> parentIds = Collections.singleton(menuDO.getId()); + for (int i = 0; i < Short.MAX_VALUE; i++) { // 使用 Short.MAX_VALUE 避免 bug 场景下,存在死循环 + // 查询当前层,所有的子应用菜单 + List<MenuDO> menus = menuService.selectListByParentId(parentIds); + // 1. 如果没有子菜单,则结束遍历 + if (CollUtil.isEmpty(menus)) { + break; + } + // 2. 如果有子应用菜单,继续遍历 + children.addAll(menus); + parentIds = convertSet(menus, MenuDO::getId); + } + children.retainAll(menuList); + List<MenuDO> tempChildren = new LinkedList<>(); + //为每一个二级菜单增加一个隐藏父级目录 + children.stream().forEach(menu -> { + if (menu.getType().equals(MenuTypeEnum.MENU.getType()) && menu.getParentId().equals(menuDO.getId())) { + MenuDO parentMenu = BeanUtils.toBean(menu, MenuDO.class); + parentMenu.setId(System.currentTimeMillis() + (int) (Math.random() * (99999 - 10000 + 1)) + 10000); + parentMenu.setType(MenuTypeEnum.DIR.getType()); + parentMenu.setVisible(true); + parentMenu.setAlwaysShow(false); + parentMenu.setParentId(menuDO.getId()); + menu.setParentId(parentMenu.getId()); + tempChildren.add(parentMenu); + tempChildren.add(menu); + } else { + tempChildren.add(menu); + } + }); + menuVOS = AuthConvert.INSTANCE.buildMenuTree(tempChildren, menuDO.getId(), menuDO.getPath()); + // 2. 拼接结果返回 + return success(menuVOS); } // ========== 短信登录相关 ========== diff --git a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/oauth2/OAuth2OpenController.java b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/oauth2/OAuth2OpenController.java index a1fe484..44791bf 100644 --- a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/oauth2/OAuth2OpenController.java +++ b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/oauth2/OAuth2OpenController.java @@ -11,7 +11,6 @@ import com.iailab.module.system.controller.admin.oauth2.vo.open.OAuth2OpenAccessTokenRespVO; import com.iailab.module.system.controller.admin.oauth2.vo.open.OAuth2OpenAuthorizeInfoRespVO; import com.iailab.module.system.controller.admin.oauth2.vo.open.OAuth2OpenCheckTokenRespVO; -import com.iailab.module.system.controller.admin.oauth2.vo.open.OAuth2OpenLoginReqVO; import com.iailab.module.system.convert.oauth2.OAuth2OpenConvert; import com.iailab.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO; import com.iailab.module.system.dal.dataobject.oauth2.OAuth2ApproveDO; @@ -85,16 +84,25 @@ @PostMapping("/token") @PermitAll @Operation(summary = "获得访问令牌", description = "适合 code 授权码模式,或者 implicit 简化模式;在 sso.vue 单点登录界面被【获取】调用") + @Parameters({ + @Parameter(name = "grant_type", required = true, description = "授权类型", example = "code"), + @Parameter(name = "code", description = "授权范围", example = "userinfo.read"), + @Parameter(name = "redirect_uri", description = "重定向 URI", example = "https://www.baidu.com"), + @Parameter(name = "state", description = "状态", example = "1"), + @Parameter(name = "username", example = "tudou"), + @Parameter(name = "password", example = "cai"), // 多个使用空格分隔 + @Parameter(name = "scope", example = "user_info"), + @Parameter(name = "refresh_token", example = "123424233"), + }) public CommonResult<OAuth2OpenAccessTokenRespVO> postAccessToken(HttpServletRequest request, - @RequestBody OAuth2OpenLoginReqVO openLoginReqVO) { - String code = openLoginReqVO.getCode(); - String scope = openLoginReqVO.getScope(); - String grantType = openLoginReqVO.getGrantType(); - String redirectUri = openLoginReqVO.getRedirectUri(); - String state = openLoginReqVO.getState(); - String username = openLoginReqVO.getUsername(); - String password = openLoginReqVO.getPassword(); - String refreshToken = openLoginReqVO.getRefreshToken(); + @RequestParam("grant_type") String grantType, + @RequestParam(value = "code", required = false) String code, // 授权码模式 + @RequestParam(value = "redirect_uri", required = false) String redirectUri, // 授权码模式 + @RequestParam(value = "state", required = false) String state, // 授权码模式 + @RequestParam(value = "username", required = false) String username, // 密码模式 + @RequestParam(value = "password", required = false) String password, // 密码模式 + @RequestParam(value = "scope", required = false) String scope, // 密码模式 + @RequestParam(value = "refresh_token", required = false) String refreshToken) { // 刷新模式 List<String> scopes = OAuth2Utils.buildScopes(scope); // 1.1 校验授权类型 OAuth2GrantTypeEnum grantTypeEnum = OAuth2GrantTypeEnum.getByGrantType(grantType); diff --git a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/oauth2/vo/open/OAuth2OpenLoginReqVO.java b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/oauth2/vo/open/OAuth2OpenLoginReqVO.java index f67ff9e..bab9c76 100644 --- a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/oauth2/vo/open/OAuth2OpenLoginReqVO.java +++ b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/oauth2/vo/open/OAuth2OpenLoginReqVO.java @@ -21,6 +21,12 @@ @Builder public class OAuth2OpenLoginReqVO { +// @Schema(description = "客户端编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "tudou") +// private String clientId; +// +// @Schema(description = "客户端密钥", requiredMode = Schema.RequiredMode.REQUIRED, example = "fan") +// private String clientSecret; + @Schema(description = "授权类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "password") private String grantType; diff --git a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/permission/PermissionController.java b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/permission/PermissionController.java index 0bf9e24..2aa6247 100644 --- a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/permission/PermissionController.java +++ b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/permission/PermissionController.java @@ -63,14 +63,14 @@ return success(true); } - @PostMapping("/assign-role-app-menu") - @Operation(summary = "赋予角色菜单") - @PreAuthorize("@ss.hasPermission('system:permission:assign-role-menu')") - public CommonResult<Boolean> assignRoleAppMenu(@Validated @RequestBody PermissionAssignRoleMenuReqVO reqVO) { - // 执行菜单的分配 - permissionService.assignRoleAppMenu(reqVO.getRoleId(), reqVO.getMenuIds()); - return success(true); - } +// @PostMapping("/assign-role-app-menu") +// @Operation(summary = "赋予角色菜单") +// @PreAuthorize("@ss.hasPermission('system:permission:assign-role-menu')") +// public CommonResult<Boolean> assignRoleAppMenu(@Validated @RequestBody PermissionAssignRoleMenuReqVO reqVO) { +// // 执行菜单的分配 +// permissionService.assignRoleAppMenu(reqVO.getRoleId(), reqVO.getMenuIds()); +// return success(true); +// } @PostMapping("/assign-role-data-scope") @Operation(summary = "赋予角色数据权限") diff --git a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/convert/auth/AuthConvert.java b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/convert/auth/AuthConvert.java index 446a341..e8e73c5 100644 --- a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/convert/auth/AuthConvert.java +++ b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/convert/auth/AuthConvert.java @@ -161,7 +161,6 @@ parentNode.setChildren(new ArrayList<>()); } parentNode.getChildren().add(childNode); - }); // 获得到所有的根节点 List<AuthPermissionInfoRespVO.MenuVO> menuVOS = filterList(treeNodeMap.values(), node -> id.equals(node.getParentId())); diff --git a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/app/AppService.java b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/app/AppService.java index e903e4f..c754288 100644 --- a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/app/AppService.java +++ b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/app/AppService.java @@ -1,8 +1,10 @@ package com.iailab.module.system.service.app; import com.iailab.framework.common.pojo.PageResult; +import com.iailab.module.system.api.app.dto.AppMenuRespDTO; import com.iailab.module.system.controller.admin.app.vo.AppPageReqVO; import com.iailab.module.system.controller.admin.app.vo.AppSaveReqVO; +import com.iailab.module.system.controller.admin.auth.vo.AuthPermissionInfoRespVO; import com.iailab.module.system.dal.dataobject.app.AppDO; import java.util.List; @@ -28,6 +30,8 @@ AppDO getAppByTenantId(Long tenantId); -// List<AppMenuRespDTO> getAppMenu(Long id); + List<AuthPermissionInfoRespVO.MenuVO> getAppMenu(Long id); + + List<AppDO> selectBatchIds(List<Long> ids); } diff --git a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/app/AppServiceImpl.java b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/app/AppServiceImpl.java index c090de3..9956f88 100644 --- a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/app/AppServiceImpl.java +++ b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/app/AppServiceImpl.java @@ -1,5 +1,6 @@ package com.iailab.module.system.service.app; +import cn.hutool.core.collection.CollUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.iailab.framework.common.pojo.PageResult; @@ -7,8 +8,11 @@ import com.iailab.framework.mybatis.core.query.LambdaQueryWrapperX; import com.iailab.framework.security.core.util.SecurityFrameworkUtils; import com.iailab.framework.tenant.core.aop.TenantIgnore; +import com.iailab.module.system.api.app.dto.AppMenuRespDTO; import com.iailab.module.system.controller.admin.app.vo.AppPageReqVO; import com.iailab.module.system.controller.admin.app.vo.AppSaveReqVO; +import com.iailab.module.system.controller.admin.auth.vo.AuthPermissionInfoRespVO; +import com.iailab.module.system.convert.auth.AuthConvert; import com.iailab.module.system.dal.dataobject.app.AppDO; import com.iailab.module.system.dal.dataobject.permission.MenuDO; import com.iailab.module.system.dal.dataobject.permission.RoleDO; @@ -22,6 +26,7 @@ import com.iailab.module.system.dal.mysql.tenant.TenantMapper; import com.iailab.module.system.dal.mysql.tenant.TenantPackageMapper; import com.iailab.module.system.enums.permission.MenuTypeEnum; +import com.iailab.module.system.service.permission.MenuService; import com.iailab.module.system.service.permission.PermissionService; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.ObjectUtils; @@ -32,6 +37,7 @@ import java.util.*; import static com.iailab.framework.common.exception.util.ServiceExceptionUtil.exception; +import static com.iailab.framework.common.util.collection.CollectionUtils.convertSet; import static com.iailab.framework.tenant.core.context.TenantContextHolder.getTenantId; import static com.iailab.module.system.enums.ErrorCodeConstants.MENU_EXISTS_CHILDREN; import static com.iailab.module.system.enums.ErrorCodeConstants.MENU_NOT_EXISTS; @@ -65,6 +71,9 @@ @Resource private TenantMapper tenantMapper; + + @Resource + private MenuService menuService; @Override @@ -124,13 +133,7 @@ //查询系统应用菜单 // List<MenuDO> menuDOS = menuMapper.selectList(menuDOLambdaQueryWrapperX); // List<AppDO> systemApps = convertMenuToApp(menuDOS); - //创建一个系统管理应用菜单 - AppDO aDo = new AppDO(); - aDo.setAppType(1); - aDo.setAppName("系统管理"); - aDo.setOrderNum(0); List<AppDO> systemApps = new ArrayList<>(); - systemApps.add(aDo); List<AppDO> appDOS = appMapper.selectList(); //暂时先遍历处理应用菜单和应用类型 appDOS.stream().forEach(appDO -> { @@ -157,27 +160,28 @@ } } -// @Override -// public List<MenuRespDTO> getAppMenu(Long id) { -// -// List<MenuDO> children = new LinkedList<>(); -// // 遍历每一层 -// Collection<Long> parentIds = Collections.singleton(id); -// for (int i = 0; i < Short.MAX_VALUE; i++) { // 使用 Short.MAX_VALUE 避免 bug 场景下,存在死循环 -// // 查询当前层,所有的子应用菜单 -// List<MenuDO> menus = menuMapper.selectListByParentId(parentIds); -// // 1. 如果没有子菜单,则结束遍历 -// if (CollUtil.isEmpty(menus)) { -// break; -// } -// // 2. 如果有子应用菜单,继续遍历 -// children.addAll(menus); -// parentIds = convertSet(menus, MenuDO::getId); -// } -// children = menuService.filterDisableMenus(children); -// return AuthConvert.INSTANCE.buildMenuTree(id, children); -// -// } + @Override + public List<AuthPermissionInfoRespVO.MenuVO> getAppMenu(Long id) { + MenuDO menuDO = menuMapper.selectById(id); + + List<MenuDO> children = new LinkedList<>(); + // 遍历每一层 + Collection<Long> parentIds = Collections.singleton(id); + for (int i = 0; i < Short.MAX_VALUE; i++) { // 使用 Short.MAX_VALUE 避免 bug 场景下,存在死循环 + // 查询当前层,所有的子应用菜单 + List<MenuDO> menus = menuMapper.selectListByParentId(parentIds); + // 1. 如果没有子菜单,则结束遍历 + if (CollUtil.isEmpty(menus)) { + break; + } + // 2. 如果有子应用菜单,继续遍历 + children.addAll(menus); + parentIds = convertSet(menus, MenuDO::getId); + } + children = menuService.filterDisableMenus(children); + return AuthConvert.INSTANCE.buildMenuTree(children, id, menuDO.getPath()); + + } private void dealAppMenu(Integer type, AppDO app){ String loginUserNickname = SecurityFrameworkUtils.getLoginUserNickname(); @@ -192,8 +196,8 @@ menuDO.setCreator(loginUserNickname); menuDO.setCreateTime(app.getCreateTime()); menuMapper.insert(menuDO); - //内置租户角色分配菜单 - assignRoleMenu(menuDO.getId(), app.getTenantId()); +// //内置租户角色分配菜单 +// assignRoleMenu(menuDO.getId(), app.getTenantId()); } else if(type == 2){ LambdaUpdateWrapper<MenuDO> updateWrapper = new LambdaUpdateWrapper<>(); updateWrapper.eq(MenuDO::getAppId, app.getId()); @@ -207,8 +211,8 @@ menuDO.setCreator(loginUserNickname); menuDO.setCreateTime(app.getCreateTime()); menuMapper.insert(menuDO); - //内置租户角色分配菜单 - assignRoleMenu(menuDO.getId(), app.getTenantId()); +// //内置租户角色分配菜单 +// assignRoleMenu(menuDO.getId(), app.getTenantId()); } } else if(type == 3){ //删除租户、角色权限 @@ -218,23 +222,25 @@ menuWrapper.eq(MenuDO::getType, MenuTypeEnum.DIR.getType()); MenuDO menu = menuMapper.selectOne(menuWrapper); TenantDO tenantDO = tenantMapper.selectById(app.getTenantId()); - TenantPackageDO tenantPackageDO = tenantPackageMapper.selectById(tenantDO.getPackageId()); - Set<Long> menuIds = tenantPackageDO.getMenuIds(); - menuIds.remove(menu.getId()); - // 校验是否还有子菜单 - if (menuMapper.selectCountByParentId(menu.getId()) > 0) { - throw exception(MENU_EXISTS_CHILDREN); + if(ObjectUtils.isNotEmpty(menu) && ObjectUtils.isNotEmpty(tenantDO)) { + TenantPackageDO tenantPackageDO = tenantPackageMapper.selectById(tenantDO.getPackageId()); + Set<Long> menuIds = tenantPackageDO.getMenuIds(); + menuIds.remove(menu.getId()); + // 校验是否还有子菜单 + if (menuMapper.selectCountByParentId(menu.getId()) > 0) { + throw exception(MENU_EXISTS_CHILDREN); + } + // 校验删除的菜单是否存在 + if (menuMapper.selectById(menu.getId()) == null) { + throw exception(MENU_NOT_EXISTS); + } + // 标记删除 + menuMapper.deleteById(menu.getId()); + // 删除授予给角色的权限 + permissionService.processMenuDeleted(menu.getId()); + //删除菜单 + menuMapper.delete(menuWrapper); } - // 校验删除的菜单是否存在 - if (menuMapper.selectById(menu.getId()) == null) { - throw exception(MENU_NOT_EXISTS); - } - // 标记删除 - menuMapper.deleteById(menu.getId()); - // 删除授予给角色的权限 - permissionService.processMenuDeleted(menu.getId()); - //删除菜单 - menuMapper.delete(menuWrapper); } } @@ -269,4 +275,9 @@ return appDOS; } + public List<AppDO> selectBatchIds(List<Long> ids) { + List<AppDO> appDOS = appMapper.selectBatchIds(ids); + return appDOS; + } + } \ No newline at end of file diff --git a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/permission/MenuService.java b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/permission/MenuService.java index 2ab458b..ca267b6 100644 --- a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/permission/MenuService.java +++ b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/permission/MenuService.java @@ -103,6 +103,14 @@ MenuDO getMenu(Long id); /** + * 根据应用id获得菜单 + * + * @param id 菜单编号 + * @return 菜单 + */ + MenuDO getMenuByAppId(Long id); + + /** * 获得菜单数组 * * @param ids 菜单编号数组 @@ -110,4 +118,11 @@ */ List<MenuDO> getMenuList(Collection<Long> ids); + /** + * 根据父id查询菜单 + * @param ids + * @return + */ + List<MenuDO> selectListByParentId(Collection<Long> ids); + } diff --git a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/permission/MenuServiceImpl.java b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/permission/MenuServiceImpl.java index 17d7e40..d3c0c46 100644 --- a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/permission/MenuServiceImpl.java +++ b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/permission/MenuServiceImpl.java @@ -2,6 +2,7 @@ import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ObjUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.Lists; import com.iailab.framework.common.enums.CommonStatusEnum; @@ -12,16 +13,17 @@ import com.iailab.module.system.dal.dataobject.app.AppDO; import com.iailab.module.system.dal.dataobject.permission.MenuDO; import com.iailab.module.system.dal.dataobject.permission.RoleDO; +import com.iailab.module.system.dal.dataobject.permission.RoleMenuDO; import com.iailab.module.system.dal.dataobject.tenant.TenantDO; import com.iailab.module.system.dal.dataobject.tenant.TenantPackageDO; import com.iailab.module.system.dal.mysql.permission.MenuMapper; +import com.iailab.module.system.dal.mysql.permission.RoleMenuMapper; import com.iailab.module.system.dal.redis.RedisKeyConstants; import com.iailab.module.system.enums.permission.MenuTypeEnum; import com.iailab.module.system.service.app.AppService; import com.iailab.module.system.service.tenant.TenantPackageService; import com.iailab.module.system.service.tenant.TenantService; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.ObjectUtils; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.Cacheable; import org.springframework.context.annotation.Lazy; @@ -30,10 +32,12 @@ import javax.annotation.Resource; import java.util.*; +import java.util.stream.Collectors; import static com.iailab.framework.common.exception.util.ServiceExceptionUtil.exception; -import static com.iailab.framework.common.util.collection.CollectionUtils.convertList; -import static com.iailab.framework.common.util.collection.CollectionUtils.convertMap; +import static com.iailab.framework.common.pojo.CommonResult.success; +import static com.iailab.framework.common.util.collection.CollectionUtils.*; +import static com.iailab.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; import static com.iailab.framework.tenant.core.context.TenantContextHolder.getTenantId; import static com.iailab.module.system.dal.dataobject.permission.MenuDO.ID_ROOT; import static com.iailab.module.system.enums.ErrorCodeConstants.*; @@ -64,6 +68,9 @@ @Resource private RoleService roleService; + + @Resource + private RoleMenuMapper roleMenuMapper; @Override @CacheEvict(value = RedisKeyConstants.PERMISSION_MENU_ID_LIST, key = "#createReqVO.permission", @@ -211,7 +218,22 @@ public List<MenuDO> getAppMenuList(MenuListReqVO reqVO) { // 获取 tenantId Long tenantId = getTenantId(); - return menuMapper.selectAppMenuList(tenantId, reqVO); + List<MenuDO> menuDOS = menuMapper.selectAppMenuList(tenantId, reqVO); + Set<Long> menuDOIds = menuDOS.stream().map(MenuDO::getId).collect(Collectors.toSet()); + // 获得角色列表 + Set<Long> roleIds = permissionService.getUserRoleIdListByUserId(getLoginUserId()); + List<RoleDO> roles = roleService.getRoleList(roleIds); + roles.removeIf(role -> !CommonStatusEnum.ENABLE.getStatus().equals(role.getStatus())); // 移除禁用的角色 + if (roles.stream().noneMatch(role -> role.getCode().equals("tenant_admin"))) { + // 获得菜单列表 + Set<Long> menuIds = permissionService.getRoleMenuListByRoleId(convertSet(roles, RoleDO::getId)); + //取交集 + menuIds.retainAll(menuDOIds); + List<MenuDO> menuList = getMenuList(menuIds); + menuList = filterDisableMenus(menuList); + return menuList; + } + return menuDOS; } @Override @@ -227,12 +249,22 @@ } @Override + public MenuDO getMenuByAppId(Long id) { + return menuMapper.selectOne(new LambdaQueryWrapper<MenuDO>().eq(MenuDO::getAppId, id).eq(MenuDO::getParentId, 0l)); + } + + @Override public List<MenuDO> getMenuList(Collection<Long> ids) { // 当 ids 为空时,返回一个空的实例对象 if (CollUtil.isEmpty(ids)) { return Lists.newArrayList(); } return menuMapper.selectBatchIds(ids); + } + + @Override + public List<MenuDO> selectListByParentId(Collection<Long> ids) { + return menuMapper.selectListByParentId(ids); } /** @@ -313,14 +345,29 @@ private void dealPermission(MenuDO menu) { Long tenantId = menu.getTenantId(); - RoleDO role = roleService.getTenantAdminRole(tenantId); + RoleDO tenantRole = roleService.getTenantAdminRole(tenantId); TenantDO tenant = tenantService.getTenant(tenantId); TenantPackageDO tenantPackage = tenantPackageService.getTenantPackage(tenant.getPackageId()); Set<Long> menuIds = tenantPackage.getMenuIds(); menuIds.add(menu.getId()); tenantPackage.setMenuIds(menuIds); tenantPackageService.updateTenantPackage(BeanUtils.toBean(tenantPackage, TenantPackageSaveReqVO.class)); - permissionService.assignRoleMenu(role.getId(), menuIds); + permissionService.assignRoleMenu(tenantRole.getId(), menuIds); + // 开发者自己创建的应用菜单默认赋权给创建者所拥有的角色 + //查询当前用户所拥有的角色 + Set<Long> roleIds = permissionService.getUserRoleIdListByUserId(getLoginUserId()); + List<RoleDO> roles = roleService.getRoleList(roleIds); + roles.removeIf(role -> !CommonStatusEnum.ENABLE.getStatus().equals(role.getStatus())); // 移除禁用的角色 + roles.removeIf(role -> tenantRole.getId().equals(role.getId())); // 移除租户管理员角色 + if (!roles.isEmpty()) { + roles.stream().forEach(roleDO -> { + RoleMenuDO roleMenuDO = new RoleMenuDO(); + roleMenuDO.setMenuId(menu.getId()); + roleMenuDO.setRoleId(roleDO.getId()); + roleMenuDO.setTenantId(tenant.getId()); + roleMenuMapper.insert(roleMenuDO); + }); + } } } diff --git a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/permission/PermissionService.java b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/permission/PermissionService.java index dfa9825..a7a5e1b 100644 --- a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/permission/PermissionService.java +++ b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/permission/PermissionService.java @@ -49,7 +49,7 @@ * @param roleId 角色编号 * @param menuIds 菜单编号集合 */ - void assignRoleAppMenu(Long roleId, Set<Long> menuIds); +// void assignRoleAppMenu(Long roleId, Set<Long> menuIds); /** * 处理角色删除时,删除关联授权数据 diff --git a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/permission/PermissionServiceImpl.java b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/permission/PermissionServiceImpl.java index a4deaf4..06ea1cb 100644 --- a/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/permission/PermissionServiceImpl.java +++ b/iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/permission/PermissionServiceImpl.java @@ -172,34 +172,34 @@ // ========== 角色-菜单的相关方法 ========== - @Override - @DSTransactional // 多数据源,使用 @DSTransactional 保证本地事务,以及数据源的切换 - @CacheEvict(value = RedisKeyConstants.MENU_ROLE_ID_LIST, - allEntries = true) // allEntries 清空所有缓存,主要一次更新涉及到的 menuIds 较多,反倒批量会更快 - public void assignRoleAppMenu(Long roleId, Set<Long> menuIds) { - // 获得角色拥有应用菜单编号 - MenuListReqVO reqVO = new MenuListReqVO(); - List<MenuDO> appMenuList = menuService.getAppMenuList(reqVO); - Set<Long> appMenuIds = convertSet(appMenuList, MenuDO::getId); - Set<Long> dbMenuIds = convertSet(roleMenuMapper.selectListByRoleId(roleId), RoleMenuDO::getMenuId); - dbMenuIds.retainAll(appMenuIds); - // 计算新增和删除的菜单编号 - Set<Long> menuIdList = CollUtil.emptyIfNull(menuIds); - Collection<Long> createMenuIds = CollUtil.subtract(menuIdList, dbMenuIds); - Collection<Long> deleteMenuIds = CollUtil.subtract(dbMenuIds, menuIdList); - // 执行新增和删除。对于已经授权的菜单,不用做任何处理 - if (CollUtil.isNotEmpty(createMenuIds)) { - roleMenuMapper.insertBatch(CollectionUtils.convertList(createMenuIds, menuId -> { - RoleMenuDO entity = new RoleMenuDO(); - entity.setRoleId(roleId); - entity.setMenuId(menuId); - return entity; - })); - } - if (CollUtil.isNotEmpty(deleteMenuIds)) { - roleMenuMapper.deleteListByRoleIdAndMenuIds(roleId, deleteMenuIds); - } - } +// @Override +// @DSTransactional // 多数据源,使用 @DSTransactional 保证本地事务,以及数据源的切换 +// @CacheEvict(value = RedisKeyConstants.MENU_ROLE_ID_LIST, +// allEntries = true) // allEntries 清空所有缓存,主要一次更新涉及到的 menuIds 较多,反倒批量会更快 +// public void assignRoleAppMenu(Long roleId, Set<Long> menuIds) { +// // 获得角色拥有应用菜单编号 +// MenuListReqVO reqVO = new MenuListReqVO(); +// List<MenuDO> appMenuList = menuService.getAppMenuList(reqVO); +// Set<Long> appMenuIds = convertSet(appMenuList, MenuDO::getId); +// Set<Long> dbMenuIds = convertSet(roleMenuMapper.selectListByRoleId(roleId), RoleMenuDO::getMenuId); +// dbMenuIds.retainAll(appMenuIds); +// // 计算新增和删除的菜单编号 +// Set<Long> menuIdList = CollUtil.emptyIfNull(menuIds); +// Collection<Long> createMenuIds = CollUtil.subtract(menuIdList, dbMenuIds); +// Collection<Long> deleteMenuIds = CollUtil.subtract(dbMenuIds, menuIdList); +// // 执行新增和删除。对于已经授权的菜单,不用做任何处理 +// if (CollUtil.isNotEmpty(createMenuIds)) { +// roleMenuMapper.insertBatch(CollectionUtils.convertList(createMenuIds, menuId -> { +// RoleMenuDO entity = new RoleMenuDO(); +// entity.setRoleId(roleId); +// entity.setMenuId(menuId); +// return entity; +// })); +// } +// if (CollUtil.isNotEmpty(deleteMenuIds)) { +// roleMenuMapper.deleteListByRoleIdAndMenuIds(roleId, deleteMenuIds); +// } +// } @Override @Transactional(rollbackFor = Exception.class) @@ -227,6 +227,10 @@ if (CollUtil.isEmpty(roleIds)) { return Collections.emptySet(); } + // 如果是管理员的情况下,获取全部菜单编号 + if (roleService.hasAnySuperAdmin(roleIds)) { + return convertSet(menuService.getMenuList(), MenuDO::getId); + } return convertSet(roleMenuMapper.selectListByRoleId(roleIds), RoleMenuDO::getMenuId); } diff --git a/iailab-module-system/iailab-module-system-biz/src/test/java/com/iailab/module/system/controller/admin/oauth2/OAuth2OpenControllerTest.java b/iailab-module-system/iailab-module-system-biz/src/test/java/com/iailab/module/system/controller/admin/oauth2/OAuth2OpenControllerTest.java index 7ad391b..fe2faaa 100644 --- a/iailab-module-system/iailab-module-system-biz/src/test/java/com/iailab/module/system/controller/admin/oauth2/OAuth2OpenControllerTest.java +++ b/iailab-module-system/iailab-module-system-biz/src/test/java/com/iailab/module/system/controller/admin/oauth2/OAuth2OpenControllerTest.java @@ -1,337 +1,337 @@ -package com.iailab.module.system.controller.admin.oauth2; - -import cn.hutool.core.collection.ListUtil; -import cn.hutool.core.date.LocalDateTimeUtil; -import cn.hutool.core.map.MapUtil; -import com.iailab.framework.common.core.KeyValue; -import com.iailab.framework.common.enums.UserTypeEnum; -import com.iailab.framework.common.exception.ErrorCode; -import com.iailab.framework.common.pojo.CommonResult; -import com.iailab.framework.common.util.collection.SetUtils; -import com.iailab.framework.common.util.object.ObjectUtils; -import com.iailab.framework.test.core.ut.BaseMockitoUnitTest; -import com.iailab.module.system.controller.admin.oauth2.vo.open.OAuth2OpenAccessTokenRespVO; -import com.iailab.module.system.controller.admin.oauth2.vo.open.OAuth2OpenAuthorizeInfoRespVO; -import com.iailab.module.system.controller.admin.oauth2.vo.open.OAuth2OpenCheckTokenRespVO; -import com.iailab.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO; -import com.iailab.module.system.dal.dataobject.oauth2.OAuth2ApproveDO; -import com.iailab.module.system.dal.dataobject.oauth2.OAuth2ClientDO; -import com.iailab.module.system.enums.oauth2.OAuth2GrantTypeEnum; -import com.iailab.module.system.service.oauth2.OAuth2ApproveService; -import com.iailab.module.system.service.oauth2.OAuth2ClientService; -import com.iailab.module.system.service.oauth2.OAuth2GrantService; -import com.iailab.module.system.service.oauth2.OAuth2TokenService; -import org.assertj.core.util.Lists; -import org.junit.jupiter.api.Test; -import org.mockito.InjectMocks; -import org.mockito.Mock; - -import javax.servlet.http.HttpServletRequest; -import java.time.LocalDateTime; -import java.time.temporal.ChronoUnit; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; - -import static com.iailab.framework.common.util.collection.SetUtils.asSet; -import static com.iailab.framework.test.core.util.AssertUtils.assertPojoEquals; -import static com.iailab.framework.test.core.util.AssertUtils.assertServiceException; -import static com.iailab.framework.test.core.util.RandomUtils.randomPojo; -import static com.iailab.framework.test.core.util.RandomUtils.randomString; -import static java.util.Arrays.asList; -import static org.hamcrest.CoreMatchers.anyOf; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.isNull; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -/** - * {@link OAuth2OpenController} 的单元测试 - * - * @author iailab - */ -public class OAuth2OpenControllerTest extends BaseMockitoUnitTest { - - @InjectMocks - private OAuth2OpenController oauth2OpenController; - - @Mock - private OAuth2GrantService oauth2GrantService; - @Mock - private OAuth2ClientService oauth2ClientService; - @Mock - private OAuth2ApproveService oauth2ApproveService; - @Mock - private OAuth2TokenService oauth2TokenService; - - @Test - public void testPostAccessToken_authorizationCode() { - // 准备参数 - String granType = OAuth2GrantTypeEnum.AUTHORIZATION_CODE.getGrantType(); - String code = randomString(); - String redirectUri = randomString(); - String state = randomString(); - HttpServletRequest request = mockRequest("test_client_id", "test_client_secret"); - // mock 方法(client) - OAuth2ClientDO client = randomPojo(OAuth2ClientDO.class).setClientId("test_client_id"); - when(oauth2ClientService.validOAuthClientFromCache(eq("test_client_id"), eq("test_client_secret"), eq(granType), eq(new ArrayList<>()), eq(redirectUri))).thenReturn(client); - - // mock 方法(访问令牌) - OAuth2AccessTokenDO accessTokenDO = randomPojo(OAuth2AccessTokenDO.class) - .setExpiresTime(LocalDateTimeUtil.offset(LocalDateTime.now(), 30000L, ChronoUnit.MILLIS)); - when(oauth2GrantService.grantAuthorizationCodeForAccessToken(eq("test_client_id"), - eq(code), eq(redirectUri), eq(state))).thenReturn(accessTokenDO); - - // 调用 - CommonResult<OAuth2OpenAccessTokenRespVO> result = oauth2OpenController.postAccessToken(request, granType, - code, redirectUri, state, null, null, null, null); - // 断言 - assertEquals(0, result.getCode()); - assertPojoEquals(accessTokenDO, result.getData()); - assertTrue(ObjectUtils.equalsAny(result.getData().getExpiresIn(), 29L, 30L)); // 执行过程会过去几毫秒 - } - - @Test - public void testPostAccessToken_password() { - // 准备参数 - String granType = OAuth2GrantTypeEnum.PASSWORD.getGrantType(); - String username = randomString(); - String password = randomString(); - String scope = "write read"; - HttpServletRequest request = mockRequest("test_client_id", "test_client_secret"); - // mock 方法(client) - OAuth2ClientDO client = randomPojo(OAuth2ClientDO.class).setClientId("test_client_id"); - when(oauth2ClientService.validOAuthClientFromCache(eq("test_client_id"), eq("test_client_secret"), - eq(granType), eq(Lists.newArrayList("write", "read")), isNull())).thenReturn(client); - - // mock 方法(访问令牌) - OAuth2AccessTokenDO accessTokenDO = randomPojo(OAuth2AccessTokenDO.class) - .setExpiresTime(LocalDateTimeUtil.offset(LocalDateTime.now(), 30000L, ChronoUnit.MILLIS)); - when(oauth2GrantService.grantPassword(eq(username), eq(password), eq("test_client_id"), - eq(Lists.newArrayList("write", "read")))).thenReturn(accessTokenDO); - - // 调用 - CommonResult<OAuth2OpenAccessTokenRespVO> result = oauth2OpenController.postAccessToken(request, granType, - null, null, null, username, password, scope, null); - // 断言 - assertEquals(0, result.getCode()); - assertPojoEquals(accessTokenDO, result.getData()); - assertTrue(ObjectUtils.equalsAny(result.getData().getExpiresIn(), 29L, 30L)); // 执行过程会过去几毫秒 - } - - @Test - public void testPostAccessToken_refreshToken() { - // 准备参数 - String granType = OAuth2GrantTypeEnum.REFRESH_TOKEN.getGrantType(); - String refreshToken = randomString(); - String password = randomString(); - HttpServletRequest request = mockRequest("test_client_id", "test_client_secret"); - // mock 方法(client) - OAuth2ClientDO client = randomPojo(OAuth2ClientDO.class).setClientId("test_client_id"); - when(oauth2ClientService.validOAuthClientFromCache(eq("test_client_id"), eq("test_client_secret"), - eq(granType), eq(Lists.newArrayList()), isNull())).thenReturn(client); - - // mock 方法(访问令牌) - OAuth2AccessTokenDO accessTokenDO = randomPojo(OAuth2AccessTokenDO.class) - .setExpiresTime(LocalDateTimeUtil.offset(LocalDateTime.now(), 30000L, ChronoUnit.MILLIS)); - when(oauth2GrantService.grantRefreshToken(eq(refreshToken), eq("test_client_id"))).thenReturn(accessTokenDO); - - // 调用 - CommonResult<OAuth2OpenAccessTokenRespVO> result = oauth2OpenController.postAccessToken(request, granType, - null, null, null, null, password, null, refreshToken); - // 断言 - assertEquals(0, result.getCode()); - assertPojoEquals(accessTokenDO, result.getData()); - assertTrue(ObjectUtils.equalsAny(result.getData().getExpiresIn(), 29L, 30L)); // 执行过程会过去几毫秒 - } - - @Test - public void testPostAccessToken_implicit() { - // 调用,并断言 - assertServiceException(() -> oauth2OpenController.postAccessToken(null, - OAuth2GrantTypeEnum.IMPLICIT.getGrantType(), null, null, null, - null, null, null, null), - new ErrorCode(400, "Token 接口不支持 implicit 授权模式")); - } - - @Test - public void testRevokeToken() { - // 准备参数 - HttpServletRequest request = mockRequest("demo_client_id", "demo_client_secret"); - String token = randomString(); - // mock 方法(client) - OAuth2ClientDO client = randomPojo(OAuth2ClientDO.class).setClientId("demo_client_id"); - when(oauth2ClientService.validOAuthClientFromCache(eq("demo_client_id"), - eq("demo_client_secret"), isNull(), isNull(), isNull())).thenReturn(client); - // mock 方法(移除) - when(oauth2GrantService.revokeToken(eq("demo_client_id"), eq(token))).thenReturn(true); - - // 调用 - CommonResult<Boolean> result = oauth2OpenController.revokeToken(request, token); - // 断言 - assertEquals(0, result.getCode()); - assertTrue(result.getData()); - } - - @Test - public void testCheckToken() { - // 准备参数 - HttpServletRequest request = mockRequest("demo_client_id", "demo_client_secret"); - String token = randomString(); - // mock 方法 - OAuth2AccessTokenDO accessTokenDO = randomPojo(OAuth2AccessTokenDO.class).setUserType(UserTypeEnum.ADMIN.getValue()).setExpiresTime(LocalDateTimeUtil.of(1653485731195L)); - when(oauth2TokenService.checkAccessToken(eq(token))).thenReturn(accessTokenDO); - - // 调用 - CommonResult<OAuth2OpenCheckTokenRespVO> result = oauth2OpenController.checkToken(request, token); - // 断言 - assertEquals(0, result.getCode()); - assertPojoEquals(accessTokenDO, result.getData()); - assertEquals(1653485731L, result.getData().getExp()); // 执行过程会过去几毫秒 - } - - @Test - public void testAuthorize() { - // 准备参数 - String clientId = randomString(); - // mock 方法(client) - OAuth2ClientDO client = randomPojo(OAuth2ClientDO.class).setClientId("demo_client_id").setScopes(ListUtil.toList("read", "write", "all")); - when(oauth2ClientService.validOAuthClientFromCache(eq(clientId))).thenReturn(client); - // mock 方法(approve) - List<OAuth2ApproveDO> approves = asList( - randomPojo(OAuth2ApproveDO.class).setScope("read").setApproved(true), - randomPojo(OAuth2ApproveDO.class).setScope("write").setApproved(false)); - when(oauth2ApproveService.getApproveList(isNull(), eq(UserTypeEnum.ADMIN.getValue()), eq(clientId))).thenReturn(approves); - - // 调用 - CommonResult<OAuth2OpenAuthorizeInfoRespVO> result = oauth2OpenController.authorize(clientId); - // 断言 - assertEquals(0, result.getCode()); - assertPojoEquals(client, result.getData().getClient()); - assertEquals(new KeyValue<>("read", true), result.getData().getScopes().get(0)); - assertEquals(new KeyValue<>("write", false), result.getData().getScopes().get(1)); - assertEquals(new KeyValue<>("all", false), result.getData().getScopes().get(2)); - } - - @Test - public void testApproveOrDeny_grantTypeError() { - // 调用,并断言 - assertServiceException(() -> oauth2OpenController.approveOrDeny(randomString(), null, - null, null, null, null), - new ErrorCode(400, "response_type 参数值只允许 code 和 token")); - } - - @Test // autoApprove = true,但是不通过 - public void testApproveOrDeny_autoApproveNo() { - // 准备参数 - String responseType = "code"; - String clientId = randomString(); - String scope = "{\"read\": true, \"write\": false}"; - String redirectUri = randomString(); - String state = randomString(); - // mock 方法 - OAuth2ClientDO client = randomPojo(OAuth2ClientDO.class); - when(oauth2ClientService.validOAuthClientFromCache(eq(clientId), isNull(), eq("authorization_code"), - eq(asSet("read", "write")), eq(redirectUri))).thenReturn(client); - - // 调用 - CommonResult<String> result = oauth2OpenController.approveOrDeny(responseType, clientId, - scope, redirectUri, true, state); - // 断言 - assertEquals(0, result.getCode()); - assertNull(result.getData()); - } - - @Test // autoApprove = false,但是不通过 - public void testApproveOrDeny_ApproveNo() { - // 准备参数 - String responseType = "token"; - String clientId = randomString(); - String scope = "{\"read\": true, \"write\": false}"; - String redirectUri = "https://www.baidu.com"; - String state = "test"; - // mock 方法 - OAuth2ClientDO client = randomPojo(OAuth2ClientDO.class); - when(oauth2ClientService.validOAuthClientFromCache(eq(clientId), isNull(), eq("implicit"), - eq(asSet("read", "write")), eq(redirectUri))).thenReturn(client); - - // 调用 - CommonResult<String> result = oauth2OpenController.approveOrDeny(responseType, clientId, - scope, redirectUri, false, state); - // 断言 - assertEquals(0, result.getCode()); - assertEquals("https://www.baidu.com#error=access_denied&error_description=User%20denied%20access&state=test", result.getData()); - } - - @Test // autoApprove = true,通过 + token - public void testApproveOrDeny_autoApproveWithToken() { - // 准备参数 - String responseType = "token"; - String clientId = randomString(); - String scope = "{\"read\": true, \"write\": false}"; - String redirectUri = "https://www.baidu.com"; - String state = "test"; - // mock 方法(client) - OAuth2ClientDO client = randomPojo(OAuth2ClientDO.class).setClientId(clientId).setAdditionalInformation(null); - when(oauth2ClientService.validOAuthClientFromCache(eq(clientId), isNull(), eq("implicit"), - eq(asSet("read", "write")), eq(redirectUri))).thenReturn(client); - // mock 方法(场景一) - when(oauth2ApproveService.checkForPreApproval(isNull(), eq(UserTypeEnum.ADMIN.getValue()), - eq(clientId), eq(SetUtils.asSet("read", "write")))).thenReturn(true); - // mock 方法(访问令牌) - OAuth2AccessTokenDO accessTokenDO = randomPojo(OAuth2AccessTokenDO.class) - .setAccessToken("test_access_token").setExpiresTime(LocalDateTimeUtil.offset(LocalDateTime.now(), 30010L, ChronoUnit.MILLIS)); - when(oauth2GrantService.grantImplicit(isNull(), eq(UserTypeEnum.ADMIN.getValue()), - eq(clientId), eq(ListUtil.toList("read")))).thenReturn(accessTokenDO); - - // 调用 - CommonResult<String> result = oauth2OpenController.approveOrDeny(responseType, clientId, - scope, redirectUri, true, state); - // 断言 - assertEquals(0, result.getCode()); - assertThat(result.getData(), anyOf( // 29 和 30 都有一定概率,主要是时间计算 - is("https://www.baidu.com#access_token=test_access_token&token_type=bearer&state=test&expires_in=29&scope=read"), - is("https://www.baidu.com#access_token=test_access_token&token_type=bearer&state=test&expires_in=30&scope=read") - )); - } - - @Test // autoApprove = false,通过 + code - public void testApproveOrDeny_approveWithCode() { - // 准备参数 - String responseType = "code"; - String clientId = randomString(); - String scope = "{\"read\": true, \"write\": false}"; - String redirectUri = "https://www.baidu.com"; - String state = "test"; - // mock 方法(client) - OAuth2ClientDO client = randomPojo(OAuth2ClientDO.class).setClientId(clientId).setAdditionalInformation(null); - when(oauth2ClientService.validOAuthClientFromCache(eq(clientId), isNull(), eq("authorization_code"), - eq(asSet("read", "write")), eq(redirectUri))).thenReturn(client); - // mock 方法(场景二) - when(oauth2ApproveService.updateAfterApproval(isNull(), eq(UserTypeEnum.ADMIN.getValue()), eq(clientId), - eq(MapUtil.builder(new LinkedHashMap<String, Boolean>()).put("read", true).put("write", false).build()))) - .thenReturn(true); - // mock 方法(访问令牌) - String authorizationCode = "test_code"; - when(oauth2GrantService.grantAuthorizationCodeForCode(isNull(), eq(UserTypeEnum.ADMIN.getValue()), - eq(clientId), eq(ListUtil.toList("read")), eq(redirectUri), eq(state))).thenReturn(authorizationCode); - - // 调用 - CommonResult<String> result = oauth2OpenController.approveOrDeny(responseType, clientId, - scope, redirectUri, false, state); - // 断言 - assertEquals(0, result.getCode()); - assertEquals("https://www.baidu.com?code=test_code&state=test", result.getData()); - } - - private HttpServletRequest mockRequest(String clientId, String secret) { - HttpServletRequest request = mock(HttpServletRequest.class); - when(request.getParameter(eq("client_id"))).thenReturn(clientId); - when(request.getParameter(eq("client_secret"))).thenReturn(secret); - return request; - } - -} +//package com.iailab.module.system.controller.admin.oauth2; +// +//import cn.hutool.core.collection.ListUtil; +//import cn.hutool.core.date.LocalDateTimeUtil; +//import cn.hutool.core.map.MapUtil; +//import com.iailab.framework.common.core.KeyValue; +//import com.iailab.framework.common.enums.UserTypeEnum; +//import com.iailab.framework.common.exception.ErrorCode; +//import com.iailab.framework.common.pojo.CommonResult; +//import com.iailab.framework.common.util.collection.SetUtils; +//import com.iailab.framework.common.util.object.ObjectUtils; +//import com.iailab.framework.test.core.ut.BaseMockitoUnitTest; +//import com.iailab.module.system.controller.admin.oauth2.vo.open.OAuth2OpenAccessTokenRespVO; +//import com.iailab.module.system.controller.admin.oauth2.vo.open.OAuth2OpenAuthorizeInfoRespVO; +//import com.iailab.module.system.controller.admin.oauth2.vo.open.OAuth2OpenCheckTokenRespVO; +//import com.iailab.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO; +//import com.iailab.module.system.dal.dataobject.oauth2.OAuth2ApproveDO; +//import com.iailab.module.system.dal.dataobject.oauth2.OAuth2ClientDO; +//import com.iailab.module.system.enums.oauth2.OAuth2GrantTypeEnum; +//import com.iailab.module.system.service.oauth2.OAuth2ApproveService; +//import com.iailab.module.system.service.oauth2.OAuth2ClientService; +//import com.iailab.module.system.service.oauth2.OAuth2GrantService; +//import com.iailab.module.system.service.oauth2.OAuth2TokenService; +//import org.assertj.core.util.Lists; +//import org.junit.jupiter.api.Test; +//import org.mockito.InjectMocks; +//import org.mockito.Mock; +// +//import javax.servlet.http.HttpServletRequest; +//import java.time.LocalDateTime; +//import java.time.temporal.ChronoUnit; +//import java.util.ArrayList; +//import java.util.LinkedHashMap; +//import java.util.List; +// +//import static com.iailab.framework.common.util.collection.SetUtils.asSet; +//import static com.iailab.framework.test.core.util.AssertUtils.assertPojoEquals; +//import static com.iailab.framework.test.core.util.AssertUtils.assertServiceException; +//import static com.iailab.framework.test.core.util.RandomUtils.randomPojo; +//import static com.iailab.framework.test.core.util.RandomUtils.randomString; +//import static java.util.Arrays.asList; +//import static org.hamcrest.CoreMatchers.anyOf; +//import static org.hamcrest.CoreMatchers.is; +//import static org.hamcrest.MatcherAssert.assertThat; +//import static org.junit.jupiter.api.Assertions.*; +//import static org.mockito.ArgumentMatchers.eq; +//import static org.mockito.ArgumentMatchers.isNull; +//import static org.mockito.Mockito.mock; +//import static org.mockito.Mockito.when; +// +///** +// * {@link OAuth2OpenController} 的单元测试 +// * +// * @author iailab +// */ +//public class OAuth2OpenControllerTest extends BaseMockitoUnitTest { +// +// @InjectMocks +// private OAuth2OpenController oauth2OpenController; +// +// @Mock +// private OAuth2GrantService oauth2GrantService; +// @Mock +// private OAuth2ClientService oauth2ClientService; +// @Mock +// private OAuth2ApproveService oauth2ApproveService; +// @Mock +// private OAuth2TokenService oauth2TokenService; +// +// @Test +// public void testPostAccessToken_authorizationCode() { +// // 准备参数 +// String granType = OAuth2GrantTypeEnum.AUTHORIZATION_CODE.getGrantType(); +// String code = randomString(); +// String redirectUri = randomString(); +// String state = randomString(); +// HttpServletRequest request = mockRequest("test_client_id", "test_client_secret"); +// // mock 方法(client) +// OAuth2ClientDO client = randomPojo(OAuth2ClientDO.class).setClientId("test_client_id"); +// when(oauth2ClientService.validOAuthClientFromCache(eq("test_client_id"), eq("test_client_secret"), eq(granType), eq(new ArrayList<>()), eq(redirectUri))).thenReturn(client); +// +// // mock 方法(访问令牌) +// OAuth2AccessTokenDO accessTokenDO = randomPojo(OAuth2AccessTokenDO.class) +// .setExpiresTime(LocalDateTimeUtil.offset(LocalDateTime.now(), 30000L, ChronoUnit.MILLIS)); +// when(oauth2GrantService.grantAuthorizationCodeForAccessToken(eq("test_client_id"), +// eq(code), eq(redirectUri), eq(state))).thenReturn(accessTokenDO); +// +// // 调用 +// CommonResult<OAuth2OpenAccessTokenRespVO> result = oauth2OpenController.postAccessToken(request, granType, +// code, redirectUri, state, null, null, null, null); +// // 断言 +// assertEquals(0, result.getCode()); +// assertPojoEquals(accessTokenDO, result.getData()); +// assertTrue(ObjectUtils.equalsAny(result.getData().getExpiresIn(), 29L, 30L)); // 执行过程会过去几毫秒 +// } +// +// @Test +// public void testPostAccessToken_password() { +// // 准备参数 +// String granType = OAuth2GrantTypeEnum.PASSWORD.getGrantType(); +// String username = randomString(); +// String password = randomString(); +// String scope = "write read"; +// HttpServletRequest request = mockRequest("test_client_id", "test_client_secret"); +// // mock 方法(client) +// OAuth2ClientDO client = randomPojo(OAuth2ClientDO.class).setClientId("test_client_id"); +// when(oauth2ClientService.validOAuthClientFromCache(eq("test_client_id"), eq("test_client_secret"), +// eq(granType), eq(Lists.newArrayList("write", "read")), isNull())).thenReturn(client); +// +// // mock 方法(访问令牌) +// OAuth2AccessTokenDO accessTokenDO = randomPojo(OAuth2AccessTokenDO.class) +// .setExpiresTime(LocalDateTimeUtil.offset(LocalDateTime.now(), 30000L, ChronoUnit.MILLIS)); +// when(oauth2GrantService.grantPassword(eq(username), eq(password), eq("test_client_id"), +// eq(Lists.newArrayList("write", "read")))).thenReturn(accessTokenDO); +// +// // 调用 +// CommonResult<OAuth2OpenAccessTokenRespVO> result = oauth2OpenController.postAccessToken(request, granType, +// null, null, null, username, password, scope, null); +// // 断言 +// assertEquals(0, result.getCode()); +// assertPojoEquals(accessTokenDO, result.getData()); +// assertTrue(ObjectUtils.equalsAny(result.getData().getExpiresIn(), 29L, 30L)); // 执行过程会过去几毫秒 +// } +// +// @Test +// public void testPostAccessToken_refreshToken() { +// // 准备参数 +// String granType = OAuth2GrantTypeEnum.REFRESH_TOKEN.getGrantType(); +// String refreshToken = randomString(); +// String password = randomString(); +// HttpServletRequest request = mockRequest("test_client_id", "test_client_secret"); +// // mock 方法(client) +// OAuth2ClientDO client = randomPojo(OAuth2ClientDO.class).setClientId("test_client_id"); +// when(oauth2ClientService.validOAuthClientFromCache(eq("test_client_id"), eq("test_client_secret"), +// eq(granType), eq(Lists.newArrayList()), isNull())).thenReturn(client); +// +// // mock 方法(访问令牌) +// OAuth2AccessTokenDO accessTokenDO = randomPojo(OAuth2AccessTokenDO.class) +// .setExpiresTime(LocalDateTimeUtil.offset(LocalDateTime.now(), 30000L, ChronoUnit.MILLIS)); +// when(oauth2GrantService.grantRefreshToken(eq(refreshToken), eq("test_client_id"))).thenReturn(accessTokenDO); +// +// // 调用 +// CommonResult<OAuth2OpenAccessTokenRespVO> result = oauth2OpenController.postAccessToken(request, granType, +// null, null, null, null, password, null, refreshToken); +// // 断言 +// assertEquals(0, result.getCode()); +// assertPojoEquals(accessTokenDO, result.getData()); +// assertTrue(ObjectUtils.equalsAny(result.getData().getExpiresIn(), 29L, 30L)); // 执行过程会过去几毫秒 +// } +// +// @Test +// public void testPostAccessToken_implicit() { +// // 调用,并断言 +// assertServiceException(() -> oauth2OpenController.postAccessToken(null, +// OAuth2GrantTypeEnum.IMPLICIT.getGrantType(), null, null, null, +// null, null, null, null), +// new ErrorCode(400, "Token 接口不支持 implicit 授权模式")); +// } +// +// @Test +// public void testRevokeToken() { +// // 准备参数 +// HttpServletRequest request = mockRequest("demo_client_id", "demo_client_secret"); +// String token = randomString(); +// // mock 方法(client) +// OAuth2ClientDO client = randomPojo(OAuth2ClientDO.class).setClientId("demo_client_id"); +// when(oauth2ClientService.validOAuthClientFromCache(eq("demo_client_id"), +// eq("demo_client_secret"), isNull(), isNull(), isNull())).thenReturn(client); +// // mock 方法(移除) +// when(oauth2GrantService.revokeToken(eq("demo_client_id"), eq(token))).thenReturn(true); +// +// // 调用 +// CommonResult<Boolean> result = oauth2OpenController.revokeToken(request, token); +// // 断言 +// assertEquals(0, result.getCode()); +// assertTrue(result.getData()); +// } +// +// @Test +// public void testCheckToken() { +// // 准备参数 +// HttpServletRequest request = mockRequest("demo_client_id", "demo_client_secret"); +// String token = randomString(); +// // mock 方法 +// OAuth2AccessTokenDO accessTokenDO = randomPojo(OAuth2AccessTokenDO.class).setUserType(UserTypeEnum.ADMIN.getValue()).setExpiresTime(LocalDateTimeUtil.of(1653485731195L)); +// when(oauth2TokenService.checkAccessToken(eq(token))).thenReturn(accessTokenDO); +// +// // 调用 +// CommonResult<OAuth2OpenCheckTokenRespVO> result = oauth2OpenController.checkToken(request, token); +// // 断言 +// assertEquals(0, result.getCode()); +// assertPojoEquals(accessTokenDO, result.getData()); +// assertEquals(1653485731L, result.getData().getExp()); // 执行过程会过去几毫秒 +// } +// +// @Test +// public void testAuthorize() { +// // 准备参数 +// String clientId = randomString(); +// // mock 方法(client) +// OAuth2ClientDO client = randomPojo(OAuth2ClientDO.class).setClientId("demo_client_id").setScopes(ListUtil.toList("read", "write", "all")); +// when(oauth2ClientService.validOAuthClientFromCache(eq(clientId))).thenReturn(client); +// // mock 方法(approve) +// List<OAuth2ApproveDO> approves = asList( +// randomPojo(OAuth2ApproveDO.class).setScope("read").setApproved(true), +// randomPojo(OAuth2ApproveDO.class).setScope("write").setApproved(false)); +// when(oauth2ApproveService.getApproveList(isNull(), eq(UserTypeEnum.ADMIN.getValue()), eq(clientId))).thenReturn(approves); +// +// // 调用 +// CommonResult<OAuth2OpenAuthorizeInfoRespVO> result = oauth2OpenController.authorize(clientId); +// // 断言 +// assertEquals(0, result.getCode()); +// assertPojoEquals(client, result.getData().getClient()); +// assertEquals(new KeyValue<>("read", true), result.getData().getScopes().get(0)); +// assertEquals(new KeyValue<>("write", false), result.getData().getScopes().get(1)); +// assertEquals(new KeyValue<>("all", false), result.getData().getScopes().get(2)); +// } +// +// @Test +// public void testApproveOrDeny_grantTypeError() { +// // 调用,并断言 +// assertServiceException(() -> oauth2OpenController.approveOrDeny(randomString(), null, +// null, null, null, null), +// new ErrorCode(400, "response_type 参数值只允许 code 和 token")); +// } +// +// @Test // autoApprove = true,但是不通过 +// public void testApproveOrDeny_autoApproveNo() { +// // 准备参数 +// String responseType = "code"; +// String clientId = randomString(); +// String scope = "{\"read\": true, \"write\": false}"; +// String redirectUri = randomString(); +// String state = randomString(); +// // mock 方法 +// OAuth2ClientDO client = randomPojo(OAuth2ClientDO.class); +// when(oauth2ClientService.validOAuthClientFromCache(eq(clientId), isNull(), eq("authorization_code"), +// eq(asSet("read", "write")), eq(redirectUri))).thenReturn(client); +// +// // 调用 +// CommonResult<String> result = oauth2OpenController.approveOrDeny(responseType, clientId, +// scope, redirectUri, true, state); +// // 断言 +// assertEquals(0, result.getCode()); +// assertNull(result.getData()); +// } +// +// @Test // autoApprove = false,但是不通过 +// public void testApproveOrDeny_ApproveNo() { +// // 准备参数 +// String responseType = "token"; +// String clientId = randomString(); +// String scope = "{\"read\": true, \"write\": false}"; +// String redirectUri = "https://www.baidu.com"; +// String state = "test"; +// // mock 方法 +// OAuth2ClientDO client = randomPojo(OAuth2ClientDO.class); +// when(oauth2ClientService.validOAuthClientFromCache(eq(clientId), isNull(), eq("implicit"), +// eq(asSet("read", "write")), eq(redirectUri))).thenReturn(client); +// +// // 调用 +// CommonResult<String> result = oauth2OpenController.approveOrDeny(responseType, clientId, +// scope, redirectUri, false, state); +// // 断言 +// assertEquals(0, result.getCode()); +// assertEquals("https://www.baidu.com#error=access_denied&error_description=User%20denied%20access&state=test", result.getData()); +// } +// +// @Test // autoApprove = true,通过 + token +// public void testApproveOrDeny_autoApproveWithToken() { +// // 准备参数 +// String responseType = "token"; +// String clientId = randomString(); +// String scope = "{\"read\": true, \"write\": false}"; +// String redirectUri = "https://www.baidu.com"; +// String state = "test"; +// // mock 方法(client) +// OAuth2ClientDO client = randomPojo(OAuth2ClientDO.class).setClientId(clientId).setAdditionalInformation(null); +// when(oauth2ClientService.validOAuthClientFromCache(eq(clientId), isNull(), eq("implicit"), +// eq(asSet("read", "write")), eq(redirectUri))).thenReturn(client); +// // mock 方法(场景一) +// when(oauth2ApproveService.checkForPreApproval(isNull(), eq(UserTypeEnum.ADMIN.getValue()), +// eq(clientId), eq(SetUtils.asSet("read", "write")))).thenReturn(true); +// // mock 方法(访问令牌) +// OAuth2AccessTokenDO accessTokenDO = randomPojo(OAuth2AccessTokenDO.class) +// .setAccessToken("test_access_token").setExpiresTime(LocalDateTimeUtil.offset(LocalDateTime.now(), 30010L, ChronoUnit.MILLIS)); +// when(oauth2GrantService.grantImplicit(isNull(), eq(UserTypeEnum.ADMIN.getValue()), +// eq(clientId), eq(ListUtil.toList("read")))).thenReturn(accessTokenDO); +// +// // 调用 +// CommonResult<String> result = oauth2OpenController.approveOrDeny(responseType, clientId, +// scope, redirectUri, true, state); +// // 断言 +// assertEquals(0, result.getCode()); +// assertThat(result.getData(), anyOf( // 29 和 30 都有一定概率,主要是时间计算 +// is("https://www.baidu.com#access_token=test_access_token&token_type=bearer&state=test&expires_in=29&scope=read"), +// is("https://www.baidu.com#access_token=test_access_token&token_type=bearer&state=test&expires_in=30&scope=read") +// )); +// } +// +// @Test // autoApprove = false,通过 + code +// public void testApproveOrDeny_approveWithCode() { +// // 准备参数 +// String responseType = "code"; +// String clientId = randomString(); +// String scope = "{\"read\": true, \"write\": false}"; +// String redirectUri = "https://www.baidu.com"; +// String state = "test"; +// // mock 方法(client) +// OAuth2ClientDO client = randomPojo(OAuth2ClientDO.class).setClientId(clientId).setAdditionalInformation(null); +// when(oauth2ClientService.validOAuthClientFromCache(eq(clientId), isNull(), eq("authorization_code"), +// eq(asSet("read", "write")), eq(redirectUri))).thenReturn(client); +// // mock 方法(场景二) +// when(oauth2ApproveService.updateAfterApproval(isNull(), eq(UserTypeEnum.ADMIN.getValue()), eq(clientId), +// eq(MapUtil.builder(new LinkedHashMap<String, Boolean>()).put("read", true).put("write", false).build()))) +// .thenReturn(true); +// // mock 方法(访问令牌) +// String authorizationCode = "test_code"; +// when(oauth2GrantService.grantAuthorizationCodeForCode(isNull(), eq(UserTypeEnum.ADMIN.getValue()), +// eq(clientId), eq(ListUtil.toList("read")), eq(redirectUri), eq(state))).thenReturn(authorizationCode); +// +// // 调用 +// CommonResult<String> result = oauth2OpenController.approveOrDeny(responseType, clientId, +// scope, redirectUri, false, state); +// // 断言 +// assertEquals(0, result.getCode()); +// assertEquals("https://www.baidu.com?code=test_code&state=test", result.getData()); +// } +// +// private HttpServletRequest mockRequest(String clientId, String secret) { +// HttpServletRequest request = mock(HttpServletRequest.class); +// when(request.getParameter(eq("client_id"))).thenReturn(clientId); +// when(request.getParameter(eq("client_secret"))).thenReturn(secret); +// return request; +// } +// +//} -- Gitblit v1.9.3