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; // ========== 上下文 ========== /** iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/api/controller/ApiIndItemController.java
@@ -2,6 +2,7 @@ import com.iailab.framework.common.pojo.CommonResult; import com.iailab.framework.common.util.object.ConvertUtils; import com.iailab.framework.tenant.core.context.TenantContextHolder; import com.iailab.module.data.api.ind.dto.ApiIndItemQueryDTO; import com.iailab.module.data.api.ind.dto.ApiIndItemValueDTO; import com.iailab.module.data.ind.collection.IndItemCollector; @@ -16,6 +17,7 @@ import org.springframework.web.bind.annotation.RestController; import javax.annotation.security.PermitAll; import java.util.ArrayList; import java.util.List; import static com.iailab.framework.common.pojo.CommonResult.success; @@ -38,8 +40,16 @@ @GetMapping("/query-ind/default-value") @Operation(summary = "查询指标默认值") public CommonResult<List<ApiIndItemValueDTO>> queryIndItemDefaultValue(@RequestParam String itemNo) { TenantContextHolder.setTenantId(161L); List<IndItemValueVO> list = indItemCollector.queryValue(itemNo); return success(ConvertUtils.sourceToTarget(list, ApiIndItemValueDTO.class)); List<ApiIndItemValueDTO> dtoList = new ArrayList<>(); list.forEach(item -> { ApiIndItemValueDTO dto = new ApiIndItemValueDTO(); dto.setDataTime(item.getDataTime()); dto.setDataValue(item.getDataValue().doubleValue()); dtoList.add(dto); }); return success(dtoList); } iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/ind/collection/utils/IndSqlUtils.java
@@ -50,6 +50,7 @@ if (indItem == null) { return result; } result.setIndItemAtom(indItem); IndDataSetDTO dataSet = indDataSetService.getDet(indItem.getDataSet()); if (dataSet == null) { return result; @@ -94,11 +95,15 @@ // 拼接SELECT StringBuilder selectSql = new StringBuilder(); if (StringUtils.isNotBlank(indItem.getDimension())){ if (StringUtils.isNotBlank(indItem.getDimension()) && StringUtils.isNotBlank(result.getIndItemAtom().getStatFunc())){ selectSql.append(indItem.getDimension()); selectSql.append(", "); selectSql.append(result.getSelectSql()); }else{ } else if(StringUtils.isBlank(indItem.getDimension()) && StringUtils.isNotBlank(result.getIndItemAtom().getStatFunc())){ selectSql.append(result.getSelectSql()); } else{ selectSql.append(result.getSelectSql()); selectSql.append(", "); selectSql.append(indItem.getTimeLabel()); @@ -188,9 +193,9 @@ whereSql.append(indItem.getTimeLabel()); whereSql.append(" <= '"); whereSql.append(DateUtils.format(indItem.getTimeEnd(), PATTERN_MON)); whereSql.append("' AND '"); whereSql.append("' AND "); whereSql.append(indItem.getTimeLabel()); whereSql.append("' >= '"); whereSql.append(" >= '"); whereSql.append(DateUtils.format(indItem.getTimeStart(), PATTERN_MON)); whereSql.append("'"); break; iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/ind/item/entity/IndItemAtomEntity.java
@@ -1,8 +1,6 @@ package com.iailab.module.data.ind.item.entity; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.*; import lombok.Data; import java.io.Serializable; @@ -32,20 +30,24 @@ /** * 数据源 */ @TableField(updateStrategy = FieldStrategy.ALWAYS) private String dataSource; /** * 数据集 */ @TableField(updateStrategy = FieldStrategy.ALWAYS) private String dataSet; /** * 使用字段 */ @TableField(updateStrategy = FieldStrategy.ALWAYS) private String usingField; /** * 统计方式 */ @TableField(updateStrategy = FieldStrategy.ALWAYS) private String statFunc; } iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/ind/item/entity/IndItemCalEntity.java
@@ -1,8 +1,6 @@ package com.iailab.module.data.ind.item.entity; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.*; import lombok.Data; import java.io.Serializable; @@ -32,5 +30,6 @@ /** * 计算表达式 */ @TableField(updateStrategy = FieldStrategy.ALWAYS) private String expression; } iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/ind/item/entity/IndItemDerEntity.java
@@ -1,8 +1,6 @@ package com.iailab.module.data.ind.item.entity; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.*; import lombok.Data; import java.io.Serializable; @@ -37,11 +35,13 @@ /** * 时间标识 */ @TableField(updateStrategy = FieldStrategy.ALWAYS) private String timeLabel; /** * 时间限定 */ @TableField(updateStrategy = FieldStrategy.ALWAYS) private String timeLimit; /** iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/ind/item/entity/IndItemEntity.java
@@ -1,9 +1,6 @@ package com.iailab.module.data.ind.item.entity; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.*; import lombok.Data; import java.io.Serializable; @@ -55,17 +52,19 @@ /** * 指标精度 */ @TableField("`precision`") @TableField(value = "`precision`", updateStrategy = FieldStrategy.ALWAYS) private Integer precision; /** * 时间粒度 */ @TableField(updateStrategy = FieldStrategy.ALWAYS) private String timeGranularity; /** * 数量单位 */ @TableField(updateStrategy = FieldStrategy.ALWAYS) private String unit; /** iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/ind/value/dto/QuerySourceValueDTO.java
@@ -1,5 +1,6 @@ package com.iailab.module.data.ind.value.dto; import com.iailab.module.data.ind.item.vo.IndItemAtomVO; import lombok.Data; /** @@ -21,4 +22,6 @@ private String groupSql; private String orderBySql; private IndItemAtomVO indItemAtom; } 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; } } 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); 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") 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); } // ========== 短信登录相关 ========== 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); 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; 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 = "赋予角色数据权限") 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())); 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); } 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; } } 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); } 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); }); } } } 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); /** * 处理角色删除时,删除关联授权数据 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); } 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; // } // //}