houzhongjian
2024-10-16 7da8f196dee8e3c526c009a4bc7f5983ece6bb97
修改平台的应用权限等相关接口
已修改14个文件
已添加1个文件
501 ■■■■ 文件已修改
iailab-framework/iailab-common-security/src/main/java/com/iailab/framework/security/core/LoginUser.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
iailab-module-infra/iailab-module-infra-biz/src/main/java/com/iailab/module/infra/controller/admin/actuator/ActuatorController.java 92 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
iailab-module-system/iailab-module-system-api/src/main/java/com/iailab/module/system/api/oauth2/OAuth2TokenApi.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/app/AppController.java 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/auth/AuthController.java 88 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/oauth2/OAuth2OpenController.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/oauth2/vo/open/OAuth2OpenLoginReqVO.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/controller/admin/permission/PermissionController.java 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/convert/auth/AuthConvert.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/app/AppService.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/app/AppServiceImpl.java 105 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/permission/MenuService.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/permission/MenuServiceImpl.java 59 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/permission/PermissionService.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
iailab-module-system/iailab-module-system-biz/src/main/java/com/iailab/module/system/service/permission/PermissionServiceImpl.java 60 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
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-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);
    }