diff --git a/admin-web/src/models/login.js b/admin-web/src/models/login.js index d7803b28d..3c34efcda 100644 --- a/admin-web/src/models/login.js +++ b/admin-web/src/models/login.js @@ -1,7 +1,7 @@ import { routerRedux } from 'dva/router'; import { stringify } from 'qs'; import { getFakeCaptcha } from '@/services/api'; -import { usernameAuthenticate } from '@/services/system'; +import { oauth2UsernameAuthenticate } from '@/services/system'; import { setAuthority } from '@/utils/authority'; import { getPageQuery } from '@/utils/utils'; import { reloadAuthorized } from '@/utils/Authorized'; @@ -16,7 +16,7 @@ export default { effects: { *login({ payload }, { call, put }) { - const response = yield call(usernameAuthenticate, payload); + const response = yield call(oauth2UsernameAuthenticate, payload); yield put({ type: 'changeLoginStatus', payload: response, @@ -24,8 +24,6 @@ export default { yield put(routerRedux.replace('/')); - debugger; - // Login successfully if (response.code === 0) { diff --git a/admin-web/src/models/menu.js b/admin-web/src/models/menu.js index 759930e74..347ecdfc9 100644 --- a/admin-web/src/models/menu.js +++ b/admin-web/src/models/menu.js @@ -3,7 +3,8 @@ import isEqual from 'lodash/isEqual'; import { formatMessage } from 'umi/locale'; import Authorized from '@/utils/Authorized'; import { menu } from '../defaultSettings'; -import { getAdminMenus, getAdminUrls } from '../services/admin'; +import { getAdminUrls } from '../services/admin'; +import { authorizationMenuResourceTree } from '../services/system'; const { check } = Authorized; @@ -84,7 +85,7 @@ const findRootMenu = (antDataMenus, rootAntDataMenu, requestDataMenu) => { let res; for (let i = 0; i < antDataMenus.length; i += 1) { const antDataMenu = antDataMenus[i]; - if (antDataMenu.path === requestDataMenu.handler) { + if (antDataMenu.path === requestDataMenu.route) { res = rootAntDataMenu; break; } @@ -98,12 +99,12 @@ const findRootMenu = (antDataMenus, rootAntDataMenu, requestDataMenu) => { const buildTreeMenu = (antMenuData, moveChildrenMenusData, requestDataMenus) => { return requestDataMenus.map(item => { - if (!item.handler) { + if (!item.route) { // root 节点 const uuid = `sms${guid()}`; const res = { icon: 'user', - name: item.displayName, + name: item.name, path: uuid, }; @@ -123,13 +124,13 @@ const buildTreeMenu = (antMenuData, moveChildrenMenusData, requestDataMenus) => } // moveChildrenMenusData 是一个 map,对比 url 地址是否存在,不存在就给一个 404 的页面 - const handleMapperData = moveChildrenMenusData[item.handler]; + const handleMapperData = moveChildrenMenusData[item.route]; if (handleMapperData) { return { ...handleMapperData, icon: 'user', - name: item.displayName, - path: item.handler, + name: item.name, + path: item.route, }; } @@ -191,7 +192,7 @@ export default { effects: { *getMenuData({ payload }, { put, call }) { - const { data } = yield call(getAdminMenus); + const { data } = yield call(authorizationMenuResourceTree); const { routes, authority } = payload; // authority 已经不适用 diff --git a/admin-web/src/services/admin.js b/admin-web/src/services/admin.js index 35cbdcc52..4ab8ada42 100644 --- a/admin-web/src/services/admin.js +++ b/admin-web/src/services/admin.js @@ -3,10 +3,6 @@ import request from '@/utils/request'; // auth -export async function getAdminMenus() { - return request('/admin-api/admins/admin/menu_resource_tree'); -} - export async function getAdminUrls(params) { return request(`/admin-api/admins/admin/url_resource_list?${stringify(params)}`); } diff --git a/admin-web/src/services/system.js b/admin-web/src/services/system.js index bfc4b016f..9ce73e9bb 100644 --- a/admin-web/src/services/system.js +++ b/admin-web/src/services/system.js @@ -1,10 +1,19 @@ import { stringify } from '@/utils/request.qs'; import request from '@/utils/request'; +// ========== OAuth2 模块 ========== -export async function usernameAuthenticate(params) { +export async function oauth2UsernameAuthenticate(params) { return request(`/system-api/admins/oauth2/username-authenticate?${stringify(params)}`, { method: 'POST', body: {}, }); } + +// ========== Authorization 模块 ========== + +export async function authorizationMenuResourceTree() { + return request('/system-api/admins/authorization/menu-resource-tree', { + method: 'GET', + }); +} diff --git a/common/common-framework/src/main/java/cn/iocoder/common/framework/mybatis/QueryWrapperX.java b/common/common-framework/src/main/java/cn/iocoder/common/framework/mybatis/QueryWrapperX.java index a82f29dd3..bf0a7fdf4 100644 --- a/common/common-framework/src/main/java/cn/iocoder/common/framework/mybatis/QueryWrapperX.java +++ b/common/common-framework/src/main/java/cn/iocoder/common/framework/mybatis/QueryWrapperX.java @@ -1,8 +1,11 @@ package cn.iocoder.common.framework.mybatis; +import cn.iocoder.common.framework.util.CollectionUtil; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import org.springframework.util.StringUtils; +import java.util.Collection; + /** * 拓展 MyBatis Plus QueryWrapper 类,主要增加如下功能: * @@ -19,6 +22,20 @@ public class QueryWrapperX extends QueryWrapper { return this; } + public QueryWrapperX inIfPresent(String column, Collection values) { + if (!CollectionUtil.isEmpty(values)) { + return (QueryWrapperX) super.in(column, values); + } + return this; + } + + public QueryWrapperX inIfPresent(String column, Object... values) { + if (!CollectionUtil.isEmpty(values)) { + return (QueryWrapperX) super.in(column, values); + } + return this; + } + public QueryWrapperX eqIfPresent(String column, Object val) { if (val != null) { return (QueryWrapperX) super.eq(column, val); diff --git a/common/mall-spring-boot-starter-security/src/main/java/cn/iocoder/mall/security/core/context/AdminSecurityContext.java b/common/mall-spring-boot-starter-security/src/main/java/cn/iocoder/mall/security/core/context/AdminSecurityContext.java index 20bf3e5a1..ba344fe6d 100644 --- a/common/mall-spring-boot-starter-security/src/main/java/cn/iocoder/mall/security/core/context/AdminSecurityContext.java +++ b/common/mall-spring-boot-starter-security/src/main/java/cn/iocoder/mall/security/core/context/AdminSecurityContext.java @@ -14,5 +14,9 @@ public class AdminSecurityContext { * 管理员编号 */ private Integer adminId; + /** + * 账号编号 + */ + private Integer accountId; } diff --git a/common/mall-spring-boot-starter-security/src/main/java/cn/iocoder/mall/security/core/context/AdminSecurityContextHolder.java b/common/mall-spring-boot-starter-security/src/main/java/cn/iocoder/mall/security/core/context/AdminSecurityContextHolder.java index 17ca066a5..3b808fa80 100644 --- a/common/mall-spring-boot-starter-security/src/main/java/cn/iocoder/mall/security/core/context/AdminSecurityContextHolder.java +++ b/common/mall-spring-boot-starter-security/src/main/java/cn/iocoder/mall/security/core/context/AdminSecurityContextHolder.java @@ -27,4 +27,12 @@ public class AdminSecurityContextHolder { SECURITY_CONTEXT.remove(); } + public static Integer getAdminId() { + return getContext().getAdminId(); + } + + public static Integer getAccountId() { + return getContext().getAccountId(); + } + } diff --git a/common/mall-spring-boot-starter-security/src/main/java/cn/iocoder/mall/security/core/interceptor/AdminSecurityInterceptor.java b/common/mall-spring-boot-starter-security/src/main/java/cn/iocoder/mall/security/core/interceptor/AdminSecurityInterceptor.java index b48e87441..695d7fb2b 100644 --- a/common/mall-spring-boot-starter-security/src/main/java/cn/iocoder/mall/security/core/interceptor/AdminSecurityInterceptor.java +++ b/common/mall-spring-boot-starter-security/src/main/java/cn/iocoder/mall/security/core/interceptor/AdminSecurityInterceptor.java @@ -6,12 +6,15 @@ import cn.iocoder.mall.security.core.context.AdminSecurityContext; import cn.iocoder.mall.security.core.context.AdminSecurityContextHolder; import cn.iocoder.mall.system.rpc.api.admin.AdminRPC; import cn.iocoder.mall.system.rpc.response.admin.AdminResponse; +import cn.iocoder.mall.web.core.util.CommonWebUtil; import org.apache.dubbo.config.annotation.Reference; import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import static cn.iocoder.mall.system.biz.enums.SystemErrorCodeEnum.ADMIN_NOT_FOUND; + public class AdminSecurityInterceptor extends HandlerInterceptorAdapter { @Reference(validation = "true", version = "${dubbo.consumer.AdminRPC.version}") @@ -19,16 +22,20 @@ public class AdminSecurityInterceptor extends HandlerInterceptorAdapter { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { - Integer accountId = AdminSecurityContextHolder.getContext().getAdminId(); + Integer accountId = CommonWebUtil.getAccountId(request); if (accountId != null) { // 获得 Admin 信息 CommonResult adminResult = adminRPC.getAdminByAccountId(accountId); if (adminResult.isError()) { throw ServiceExceptionUtil.exception(adminResult); } + if (adminResult.getData() == null) { + throw ServiceExceptionUtil.exception(ADMIN_NOT_FOUND); + } // 设置到 SecurityContext 中 AdminResponse adminResponse = adminResult.getData(); - AdminSecurityContext context = new AdminSecurityContext().setAdminId(adminResponse.getId()); + AdminSecurityContext context = new AdminSecurityContext().setAdminId(adminResponse.getId()) + .setAccountId(accountId); AdminSecurityContextHolder.setContext(context); } return true; diff --git a/common/mall-spring-boot-starter-security/src/main/java/cn/iocoder/mall/security/core/interceptor/UserSecurityInterceptor.java b/common/mall-spring-boot-starter-security/src/main/java/cn/iocoder/mall/security/core/interceptor/UserSecurityInterceptor.java index 336481fed..39eaec627 100644 --- a/common/mall-spring-boot-starter-security/src/main/java/cn/iocoder/mall/security/core/interceptor/UserSecurityInterceptor.java +++ b/common/mall-spring-boot-starter-security/src/main/java/cn/iocoder/mall/security/core/interceptor/UserSecurityInterceptor.java @@ -1,12 +1,13 @@ package cn.iocoder.mall.security.core.interceptor; +import cn.iocoder.common.framework.util.ExceptionUtil; import cn.iocoder.common.framework.util.ServiceExceptionUtil; import cn.iocoder.common.framework.vo.CommonResult; -import cn.iocoder.mall.security.core.context.AdminSecurityContextHolder; import cn.iocoder.mall.security.core.context.UserSecurityContext; import cn.iocoder.mall.security.core.context.UserSecurityContextHolder; import cn.iocoder.mall.system.rpc.api.user.UserRPC; import cn.iocoder.mall.system.rpc.response.user.UserResponse; +import cn.iocoder.mall.web.core.util.CommonWebUtil; import org.apache.dubbo.config.annotation.Reference; import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; @@ -20,13 +21,16 @@ public class UserSecurityInterceptor extends HandlerInterceptorAdapter { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { - Integer accountId = AdminSecurityContextHolder.getContext().getAdminId(); + Integer accountId = CommonWebUtil.getAccountId(request); if (accountId != null) { // 获得 Admin 信息 CommonResult userResult = userRPC.getUserByAccountId(accountId); if (userResult.isError()) { throw ServiceExceptionUtil.exception(userResult); } + if (userResult.getData() == null) { + throw ExceptionUtil.getServiceException(null); // TODO 需要完善 + } // 设置到 SecurityContext 中 UserResponse userResponse = userResult.getData(); UserSecurityContext context = new UserSecurityContext().setUserId(userResponse.getId()); diff --git a/system/system-biz-api/src/main/java/cn/iocoder/mall/system/biz/enums/authorization/ResourceIdEnum.java b/system/system-biz-api/src/main/java/cn/iocoder/mall/system/biz/enums/authorization/ResourceIdEnum.java new file mode 100644 index 000000000..b1475603d --- /dev/null +++ b/system/system-biz-api/src/main/java/cn/iocoder/mall/system/biz/enums/authorization/ResourceIdEnum.java @@ -0,0 +1,17 @@ +package cn.iocoder.mall.system.biz.enums.authorization; + +public enum ResourceIdEnum { + + ROOT(0); + + private final Integer id; + + ResourceIdEnum(Integer id) { + this.id = id; + } + + public Integer getId() { + return id; + } + +} diff --git a/system/system-biz/src/main/java/cn/iocoder/mall/system/biz/enums/authorization/ResourceTypeEnum.java b/system/system-biz-api/src/main/java/cn/iocoder/mall/system/biz/enums/authorization/ResourceTypeEnum.java similarity index 100% rename from system/system-biz/src/main/java/cn/iocoder/mall/system/biz/enums/authorization/ResourceTypeEnum.java rename to system/system-biz-api/src/main/java/cn/iocoder/mall/system/biz/enums/authorization/ResourceTypeEnum.java diff --git a/system/system-biz/src/main/java/cn/iocoder/mall/system/biz/enums/authorization/RoleCodeEnum.java b/system/system-biz-api/src/main/java/cn/iocoder/mall/system/biz/enums/authorization/RoleCodeEnum.java similarity index 100% rename from system/system-biz/src/main/java/cn/iocoder/mall/system/biz/enums/authorization/RoleCodeEnum.java rename to system/system-biz-api/src/main/java/cn/iocoder/mall/system/biz/enums/authorization/RoleCodeEnum.java diff --git a/system/system-biz-api/src/main/java/cn/iocoder/mall/system/biz/enums/authorization/RoleTypeEnum.java b/system/system-biz-api/src/main/java/cn/iocoder/mall/system/biz/enums/authorization/RoleTypeEnum.java new file mode 100644 index 000000000..d6360bf1d --- /dev/null +++ b/system/system-biz-api/src/main/java/cn/iocoder/mall/system/biz/enums/authorization/RoleTypeEnum.java @@ -0,0 +1,24 @@ +package cn.iocoder.mall.system.biz.enums.authorization; + +public enum RoleTypeEnum { + + /** + * 内置角色 + */ + SYSTEM(1), + /** + * 自定义角色 + */ + CUSTOM(2); + + private final Integer type; + + RoleTypeEnum(Integer type) { + this.type = type; + } + + public Integer getType() { + return type; + } + +} diff --git a/system/system-biz/src/main/java/cn/iocoder/mall/system/biz/dao/authorization/ResourceMapper.java b/system/system-biz/src/main/java/cn/iocoder/mall/system/biz/dao/authorization/ResourceMapper.java index 67281da61..c87c61cdd 100644 --- a/system/system-biz/src/main/java/cn/iocoder/mall/system/biz/dao/authorization/ResourceMapper.java +++ b/system/system-biz/src/main/java/cn/iocoder/mall/system/biz/dao/authorization/ResourceMapper.java @@ -4,20 +4,14 @@ import cn.iocoder.common.framework.mybatis.QueryWrapperX; import cn.iocoder.mall.system.biz.dataobject.authorization.ResourceDO; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import org.apache.ibatis.annotations.Param; import org.springframework.stereotype.Repository; import java.util.Collection; import java.util.List; -import java.util.Set; @Repository public interface ResourceMapper extends BaseMapper { - // TODO 芋艿,后续改造。 - List selectListByTypeAndRoleIds(@Param("type") Integer type, - @Param("roleIds") Set roleIds); - default ResourceDO selectByPermission(String permission) { return selectOne(new QueryWrapper().eq("permission", permission)); } @@ -26,8 +20,9 @@ public interface ResourceMapper extends BaseMapper { return selectList(new QueryWrapper().in("permission", permissions)); } - default List selectListByType(Integer type) { - return selectList(new QueryWrapperX().eqIfPresent("type", type)); + default List selectListByIdsAndType(Collection ids, Integer type) { + return selectList(new QueryWrapperX().inIfPresent("id", ids) + .eqIfPresent("type", type)); } default int selectCountByPid(Integer pid) { diff --git a/system/system-biz/src/main/java/cn/iocoder/mall/system/biz/dao/authorization/RoleResourceMapper.java b/system/system-biz/src/main/java/cn/iocoder/mall/system/biz/dao/authorization/RoleResourceMapper.java index 361bb8539..91fd9ff38 100644 --- a/system/system-biz/src/main/java/cn/iocoder/mall/system/biz/dao/authorization/RoleResourceMapper.java +++ b/system/system-biz/src/main/java/cn/iocoder/mall/system/biz/dao/authorization/RoleResourceMapper.java @@ -19,14 +19,22 @@ public interface RoleResourceMapper extends BaseMapper { */ int insertList(@Param("roleResources") List roleResources); - default List selectListByResourceId(Integer resourceId) { + default List selectListByResourceId(Integer resourceId) { return selectList(new QueryWrapper().eq("resource_id", resourceId)); } - default List selectListByResourceIds(Collection resourceIds) { + default List selectListByResourceIds(Collection resourceIds) { return selectList(new QueryWrapper().in("resource_id", resourceIds)); } + default List selectListByRoleId(Integer roleId) { + return selectList(new QueryWrapper().eq("role_id", roleId)); + } + + default List selectListByRoleIds(Collection roleIds) { + return selectList(new QueryWrapper().in("role_id", roleIds)); + } + default int deleteByResourceId(Integer resourceId) { return delete(new QueryWrapper().eq("resource_id", resourceId)); } diff --git a/system/system-biz/src/main/java/cn/iocoder/mall/system/biz/dto/authorization/AuthorizationGetResourcesByAccountIdDTO.java b/system/system-biz/src/main/java/cn/iocoder/mall/system/biz/dto/authorization/AuthorizationGetResourcesByAccountIdDTO.java new file mode 100644 index 000000000..3eec850b8 --- /dev/null +++ b/system/system-biz/src/main/java/cn/iocoder/mall/system/biz/dto/authorization/AuthorizationGetResourcesByAccountIdDTO.java @@ -0,0 +1,22 @@ +package cn.iocoder.mall.system.biz.dto.authorization; + +import lombok.Data; +import lombok.experimental.Accessors; + +import javax.validation.constraints.NotNull; + +/** + * 授权模块 - 获得账号所拥有的资源 DTO + */ +@Data +@Accessors(chain = true) +public class AuthorizationGetResourcesByAccountIdDTO { + + @NotNull(message = "账号编号不能为空") + private Integer accountId; + /** + * 资源类型 + */ + private Integer type; + +} diff --git a/system/system-biz/src/main/java/cn/iocoder/mall/system/biz/dto/authorization/ResourceGetListDTO.java b/system/system-biz/src/main/java/cn/iocoder/mall/system/biz/dto/authorization/ResourceGetListDTO.java new file mode 100644 index 000000000..53a7ac806 --- /dev/null +++ b/system/system-biz/src/main/java/cn/iocoder/mall/system/biz/dto/authorization/ResourceGetListDTO.java @@ -0,0 +1,25 @@ +package cn.iocoder.mall.system.biz.dto.authorization; + +import lombok.Data; +import lombok.experimental.Accessors; + +import java.util.Collection; + +/** + * 资源模块 - 获得资源列表 DTO + */ +@Data +@Accessors(chain = true) +public class ResourceGetListDTO { + + /** + * 资源编号数组 + */ + private Collection ids; + + /** + * 资源类型 + */ + private Integer type; + +} diff --git a/system/system-biz/src/main/java/cn/iocoder/mall/system/biz/service/authorization/AuthorizationService.java b/system/system-biz/src/main/java/cn/iocoder/mall/system/biz/service/authorization/AuthorizationService.java index 13ad3c879..7f47c2c01 100644 --- a/system/system-biz/src/main/java/cn/iocoder/mall/system/biz/service/authorization/AuthorizationService.java +++ b/system/system-biz/src/main/java/cn/iocoder/mall/system/biz/service/authorization/AuthorizationService.java @@ -1,9 +1,32 @@ package cn.iocoder.mall.system.biz.service.authorization; +import cn.iocoder.common.framework.exception.ServiceException; +import cn.iocoder.mall.system.biz.bo.authorization.ResourceBO; import cn.iocoder.mall.system.biz.dto.authorization.AuthorizationCheckPermissionsDTO; +import cn.iocoder.mall.system.biz.dto.authorization.AuthorizationGetResourcesByAccountIdDTO; +import java.util.List; + +/** + * 授权模块 - Service 接口 + */ public interface AuthorizationService { + /** + * 校验指定账号是否有指定权限。如果没有,则抛出 {@link ServiceException} 异常 + * + * @param checkPermissionsDTO 校验权限 DTO + */ void checkPermissions(AuthorizationCheckPermissionsDTO checkPermissionsDTO); + /** + * 获得指定账号的资源列表 + * + * 如果该账号为超级管理员,则返回所有资源 + * + * @param getResourcesByAccountIdDTO 查询条件 DTO + * @return 列表 + */ + List getResourcesByAccountId(AuthorizationGetResourcesByAccountIdDTO getResourcesByAccountIdDTO); + } diff --git a/system/system-biz/src/main/java/cn/iocoder/mall/system/biz/service/authorization/AuthorizationServiceImpl.java b/system/system-biz/src/main/java/cn/iocoder/mall/system/biz/service/authorization/AuthorizationServiceImpl.java index 15c1c9f03..40dabbbe7 100644 --- a/system/system-biz/src/main/java/cn/iocoder/mall/system/biz/service/authorization/AuthorizationServiceImpl.java +++ b/system/system-biz/src/main/java/cn/iocoder/mall/system/biz/service/authorization/AuthorizationServiceImpl.java @@ -8,16 +8,22 @@ import cn.iocoder.mall.system.biz.dao.authorization.RoleResourceMapper; import cn.iocoder.mall.system.biz.dataobject.authorization.AccountRoleDO; import cn.iocoder.mall.system.biz.dataobject.authorization.RoleResourceDO; import cn.iocoder.mall.system.biz.dto.authorization.AuthorizationCheckPermissionsDTO; +import cn.iocoder.mall.system.biz.dto.authorization.AuthorizationGetResourcesByAccountIdDTO; +import cn.iocoder.mall.system.biz.dto.authorization.ResourceGetListDTO; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; import static cn.iocoder.mall.system.biz.enums.SystemErrorCodeEnum.AUTHORIZATION_PERMISSION_DENY; +/** + * 授权模块 - Service 实现类 + */ @Service @Slf4j public class AuthorizationServiceImpl implements AuthorizationService { @@ -45,7 +51,7 @@ public class AuthorizationServiceImpl implements AuthorizationService { return; } // 查询权限对应资源 - List resourceBOs = resourceService.getListByPermissions(checkPermissionsDTO.getPermissions()); + List resourceBOs = resourceService.getResourcesByPermissions(checkPermissionsDTO.getPermissions()); if (CollectionUtil.isEmpty(resourceBOs)) { // 无对应资源,则认为无需权限验证 log.warn("[checkPermissions][permission({}) 未配置对应资源]", checkPermissionsDTO.getPermissions()); return; @@ -65,4 +71,26 @@ public class AuthorizationServiceImpl implements AuthorizationService { } } + @Override + public List getResourcesByAccountId(AuthorizationGetResourcesByAccountIdDTO getResourcesByAccountIdDTO) { + // 查询管理员拥有的角色关联数据 + List accountRoleDOs = accountRoleMapper.selectByAccountId(getResourcesByAccountIdDTO.getAccountId()); + if (CollectionUtil.isEmpty(accountRoleDOs)) { + return Collections.emptyList(); + } + Set roleIds = CollectionUtil.convertSet(accountRoleDOs, AccountRoleDO::getRoleId); + // 判断是否为超管。若是超管,默认有所有权限 + if (roleService.hasSuperAdmin(roleIds)) { + return resourceService.getResources(new ResourceGetListDTO().setType(getResourcesByAccountIdDTO.getType())); + } + // 查询角色拥有的资源关联数据 + List roleResourceDOs = roleResourceMapper.selectListByRoleIds(roleIds); + if (CollectionUtil.isEmpty(roleResourceDOs)) { + return Collections.emptyList(); + } + Set resourceIds = CollectionUtil.convertSet(roleResourceDOs, RoleResourceDO::getResourceId); + // 查询对应资源 + return resourceService.getResources(new ResourceGetListDTO().setIds(resourceIds).setType(getResourcesByAccountIdDTO.getType())); + } + } diff --git a/system/system-biz/src/main/java/cn/iocoder/mall/system/biz/service/authorization/ResourceService.java b/system/system-biz/src/main/java/cn/iocoder/mall/system/biz/service/authorization/ResourceService.java index b372a1836..19ac4e6ec 100644 --- a/system/system-biz/src/main/java/cn/iocoder/mall/system/biz/service/authorization/ResourceService.java +++ b/system/system-biz/src/main/java/cn/iocoder/mall/system/biz/service/authorization/ResourceService.java @@ -1,12 +1,15 @@ package cn.iocoder.mall.system.biz.service.authorization; import cn.iocoder.mall.system.biz.bo.authorization.ResourceBO; +import cn.iocoder.mall.system.biz.dto.authorization.ResourceGetListDTO; import java.util.Collection; import java.util.List; public interface ResourceService { - List getListByPermissions(Collection permissions); + List getResourcesByPermissions(Collection permissions); + + List getResources(ResourceGetListDTO getListDTO); } diff --git a/system/system-biz/src/main/java/cn/iocoder/mall/system/biz/service/authorization/ResourceServiceImpl.java b/system/system-biz/src/main/java/cn/iocoder/mall/system/biz/service/authorization/ResourceServiceImpl.java index 9d6cee1b3..637e5a053 100644 --- a/system/system-biz/src/main/java/cn/iocoder/mall/system/biz/service/authorization/ResourceServiceImpl.java +++ b/system/system-biz/src/main/java/cn/iocoder/mall/system/biz/service/authorization/ResourceServiceImpl.java @@ -4,6 +4,7 @@ import cn.iocoder.mall.system.biz.bo.authorization.ResourceBO; import cn.iocoder.mall.system.biz.convert.authorization.ResourceConvert; import cn.iocoder.mall.system.biz.dao.authorization.ResourceMapper; import cn.iocoder.mall.system.biz.dataobject.authorization.ResourceDO; +import cn.iocoder.mall.system.biz.dto.authorization.ResourceGetListDTO; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -17,9 +18,15 @@ public class ResourceServiceImpl implements ResourceService { private ResourceMapper resourceMapper; @Override - public List getListByPermissions(Collection permissions) { + public List getResourcesByPermissions(Collection permissions) { List resourceDOs = resourceMapper.selectListByPermissions(permissions); return ResourceConvert.INSTANCE.convertList(resourceDOs); } + @Override + public List getResources(ResourceGetListDTO getListDTO) { + List resourceDOs = resourceMapper.selectListByIdsAndType(getListDTO.getIds(), getListDTO.getType()); + return ResourceConvert.INSTANCE.convertList(resourceDOs); + } + } diff --git a/system/system-biz/src/main/resources/mapper/ResourceMapper.xml b/system/system-biz/src/main/resources/mapper/ResourceMapper.xml deleted file mode 100644 index 11770d79e..000000000 --- a/system/system-biz/src/main/resources/mapper/ResourceMapper.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - id, type, sort, display_name, icon, permissions, - create_time, pid, handler - - - - - diff --git a/system/system-rest/src/main/java/cn/iocoder/mall/system/rest/controller/admin/AdminsOAdminController.java b/system/system-rest/src/main/java/cn/iocoder/mall/system/rest/controller/admin/AdminsAdminController.java similarity index 91% rename from system/system-rest/src/main/java/cn/iocoder/mall/system/rest/controller/admin/AdminsOAdminController.java rename to system/system-rest/src/main/java/cn/iocoder/mall/system/rest/controller/admin/AdminsAdminController.java index a824af4e4..7e61566bf 100644 --- a/system/system-rest/src/main/java/cn/iocoder/mall/system/rest/controller/admin/AdminsOAdminController.java +++ b/system/system-rest/src/main/java/cn/iocoder/mall/system/rest/controller/admin/AdminsAdminController.java @@ -8,7 +8,7 @@ import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping(MallConstants.ROOT_PATH_ADMIN + "/admin") @Api(tags = "管理员 - 管理员 API") -public class AdminsOAdminController { +public class AdminsAdminController { diff --git a/system/system-rest/src/main/java/cn/iocoder/mall/system/rest/controller/authorization/AdminsAuthorizationController.java b/system/system-rest/src/main/java/cn/iocoder/mall/system/rest/controller/authorization/AdminsAuthorizationController.java new file mode 100644 index 000000000..9c13d6254 --- /dev/null +++ b/system/system-rest/src/main/java/cn/iocoder/mall/system/rest/controller/authorization/AdminsAuthorizationController.java @@ -0,0 +1,66 @@ +package cn.iocoder.mall.system.rest.controller.authorization; + +import cn.iocoder.common.framework.constant.MallConstants; +import cn.iocoder.common.framework.vo.CommonResult; +import cn.iocoder.mall.security.core.context.AdminSecurityContextHolder; +import cn.iocoder.mall.system.biz.bo.authorization.ResourceBO; +import cn.iocoder.mall.system.biz.dto.authorization.AuthorizationGetResourcesByAccountIdDTO; +import cn.iocoder.mall.system.biz.enums.authorization.ResourceIdEnum; +import cn.iocoder.mall.system.biz.enums.authorization.ResourceTypeEnum; +import cn.iocoder.mall.system.biz.service.authorization.AuthorizationService; +import cn.iocoder.mall.system.rest.convert.authorization.AdminsAuthorizationConvert; +import cn.iocoder.mall.system.rest.response.authorization.AdminsAuthorizationMenuTreeResponse; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.*; +import java.util.stream.Collectors; + +@RestController +@RequestMapping(MallConstants.ROOT_PATH_ADMIN + "/authorization") +@Api(tags = "管理员 - 授权 API") +@Slf4j +public class AdminsAuthorizationController { + + @Autowired + private AuthorizationService authorizationService; + + @GetMapping("/menu-resource-tree") + @ApiOperation(value = "获得当前账号的菜单资源树", notes = "以树结构返回") + public CommonResult> menuResourceTree() { + List resources = authorizationService.getResourcesByAccountId(new AuthorizationGetResourcesByAccountIdDTO() + .setAccountId(AdminSecurityContextHolder.getAccountId()).setType(ResourceTypeEnum.MENU.getValue())); + // 创建 AdminMenuTreeNodeVO Map + // 使用 LinkedHashMap 的原因,是为了排序 。实际也可以用 Stream API ,就是太丑了。 + Map treeNodeMap = new LinkedHashMap<>(); + resources.stream().sorted(Comparator.comparing(ResourceBO::getSort)) + .forEach(resourceBO -> treeNodeMap.put(resourceBO.getId(), AdminsAuthorizationConvert.INSTANCE.convert(resourceBO))); + // 处理父子关系 + treeNodeMap.values().stream() + .filter(node -> !node.getPid().equals(ResourceIdEnum.ROOT.getId())) + .forEach((childNode) -> { + // 获得父节点 + AdminsAuthorizationMenuTreeResponse parentNode = treeNodeMap.get(childNode.getPid()); + if (parentNode == null) { + log.error("[menuResourceTree][resource({}) 找不到父资源({})]", childNode.getId(), childNode.getPid()); + return; + } + if (parentNode.getChildren() == null) { // 初始化 children 数组 + parentNode.setChildren(new ArrayList<>()); + } + // 将自己添加到父节点中 + parentNode.getChildren().add(childNode); + }); + // 获得到所有的根节点 + List rootNodes = treeNodeMap.values().stream() + .filter(node -> node.getPid().equals(ResourceIdEnum.ROOT.getId())) + .collect(Collectors.toList()); + return CommonResult.success(rootNodes); + } + +} diff --git a/system/system-rest/src/main/java/cn/iocoder/mall/system/rest/convert/authorization/AdminsAuthorizationConvert.java b/system/system-rest/src/main/java/cn/iocoder/mall/system/rest/convert/authorization/AdminsAuthorizationConvert.java new file mode 100644 index 000000000..32f57595e --- /dev/null +++ b/system/system-rest/src/main/java/cn/iocoder/mall/system/rest/convert/authorization/AdminsAuthorizationConvert.java @@ -0,0 +1,15 @@ +package cn.iocoder.mall.system.rest.convert.authorization; + +import cn.iocoder.mall.system.biz.bo.authorization.ResourceBO; +import cn.iocoder.mall.system.rest.response.authorization.AdminsAuthorizationMenuTreeResponse; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +@Mapper +public interface AdminsAuthorizationConvert { + + AdminsAuthorizationConvert INSTANCE = Mappers.getMapper(AdminsAuthorizationConvert.class); + + AdminsAuthorizationMenuTreeResponse convert(ResourceBO bean); + +} diff --git a/system/system-start/src/main/java/cn/iocoder/mall/system/application/vo/admin/AdminMenuTreeNodeVO.java b/system/system-rest/src/main/java/cn/iocoder/mall/system/rest/response/authorization/AdminsAuthorizationMenuTreeResponse.java similarity index 53% rename from system/system-start/src/main/java/cn/iocoder/mall/system/application/vo/admin/AdminMenuTreeNodeVO.java rename to system/system-rest/src/main/java/cn/iocoder/mall/system/rest/response/authorization/AdminsAuthorizationMenuTreeResponse.java index e3b612b68..328c776b2 100644 --- a/system/system-start/src/main/java/cn/iocoder/mall/system/application/vo/admin/AdminMenuTreeNodeVO.java +++ b/system/system-rest/src/main/java/cn/iocoder/mall/system/rest/response/authorization/AdminsAuthorizationMenuTreeResponse.java @@ -1,4 +1,4 @@ -package cn.iocoder.mall.system.application.vo.admin; +package cn.iocoder.mall.system.rest.response.authorization; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; @@ -7,24 +7,23 @@ import lombok.experimental.Accessors; import java.util.List; -@ApiModel("管理员拥有的菜单 VO") +@ApiModel("管理员 - 授权模块 - 菜单资源树") @Data @Accessors(chain = true) -public class AdminMenuTreeNodeVO { +public class AdminsAuthorizationMenuTreeResponse { @ApiModelProperty(value = "菜单编号", required = true, example = "1") private Integer id; -// @ApiModelProperty(value = "菜单名", required = true, example = "商品管理") -// private String name; - @ApiModelProperty(value = "菜单操作", required = true, example = "/order/list") - private String handler; - @ApiModelProperty(value = "父菜单编号", required = true, example = "1", notes = "如果无父菜单,则值为 0") - private Integer pid; + @ApiModelProperty(value = "菜单名", required = true, example = "商品管理") + private String name; + @ApiModelProperty(value = "排序", required = true, example = "1") private Integer sort; - @ApiModelProperty(value = "菜单展示名", required = true, example = "商品管理") - private String displayName; + @ApiModelProperty(value = "父菜单编号", required = true, example = "1", notes = "如果无父菜单,则值为 0") + private Integer pid; + @ApiModelProperty(value = "route", required = true, example = "/order/list") + private String route; @ApiModelProperty(value = "子节点数组") - private List children; + private List children; } diff --git a/system/system-start/src/main/java/cn/iocoder/mall/system/application/controller/admins/AdminController.java b/system/system-start/src/main/java/cn/iocoder/mall/system/application/controller/admins/AdminController.java index 8bc1009ed..01ce1f5fd 100644 --- a/system/system-start/src/main/java/cn/iocoder/mall/system/application/controller/admins/AdminController.java +++ b/system/system-start/src/main/java/cn/iocoder/mall/system/application/controller/admins/AdminController.java @@ -54,35 +54,6 @@ public class AdminController { // TODO 功能:当前管理员 - @SuppressWarnings("Duplicates") - @GetMapping("/menu_resource_tree") - @ApiOperation(value = "获得当前登陆的管理员拥有的菜单权限", notes = "以树结构返回") - public CommonResult> menuResourceTree() { - List resources = resourceService.getResourcesByTypeAndRoleIds(ResourceConstants.TYPE_MENU, - AdminSecurityContextHolder.getContext().getRoleIds()); - // 创建 AdminMenuTreeNodeVO Map - Map treeNodeMap = new LinkedHashMap<>(); // 使用 LinkedHashMap 的原因,是为了排序 。实际也可以用 Stream API ,就是太丑了。 - resources.stream().sorted(Comparator.comparing(ResourceBO::getSort)).forEach(resourceBO -> treeNodeMap.put(resourceBO.getId(), ResourceConvert.INSTANCE.convert(resourceBO))); - // 处理父子关系 - treeNodeMap.values().stream() - .filter(node -> !node.getPid().equals(ResourceConstants.PID_ROOT)) - .forEach((childNode) -> { - // 获得父节点 - AdminMenuTreeNodeVO parentNode = treeNodeMap.get(childNode.getPid()); - if (parentNode.getChildren() == null) { // 初始化 children 数组 - parentNode.setChildren(new ArrayList<>()); - } - // 将自己添加到父节点中 - parentNode.getChildren().add(childNode); - }); - // 获得到所有的根节点 - List rootNodes = treeNodeMap.values().stream() - .filter(node -> node.getPid().equals(ResourceConstants.PID_ROOT)) -// .sorted(Comparator.comparing(AdminMenuTreeNodeVO::getSort)) - .collect(Collectors.toList()); - return success(rootNodes); - } - @GetMapping("/url_resource_list") @ApiOperation(value = "获得当前登陆的管理员拥有的 URL 权限列表") public CommonResult> urlResourceList() {