1. admin-web 接入菜单
2. system 迁移菜单接口
This commit is contained in:
parent
18180b3a01
commit
983c01d709
@ -1,7 +1,7 @@
|
|||||||
import { routerRedux } from 'dva/router';
|
import { routerRedux } from 'dva/router';
|
||||||
import { stringify } from 'qs';
|
import { stringify } from 'qs';
|
||||||
import { getFakeCaptcha } from '@/services/api';
|
import { getFakeCaptcha } from '@/services/api';
|
||||||
import { usernameAuthenticate } from '@/services/system';
|
import { oauth2UsernameAuthenticate } from '@/services/system';
|
||||||
import { setAuthority } from '@/utils/authority';
|
import { setAuthority } from '@/utils/authority';
|
||||||
import { getPageQuery } from '@/utils/utils';
|
import { getPageQuery } from '@/utils/utils';
|
||||||
import { reloadAuthorized } from '@/utils/Authorized';
|
import { reloadAuthorized } from '@/utils/Authorized';
|
||||||
@ -16,7 +16,7 @@ export default {
|
|||||||
|
|
||||||
effects: {
|
effects: {
|
||||||
*login({ payload }, { call, put }) {
|
*login({ payload }, { call, put }) {
|
||||||
const response = yield call(usernameAuthenticate, payload);
|
const response = yield call(oauth2UsernameAuthenticate, payload);
|
||||||
yield put({
|
yield put({
|
||||||
type: 'changeLoginStatus',
|
type: 'changeLoginStatus',
|
||||||
payload: response,
|
payload: response,
|
||||||
@ -24,8 +24,6 @@ export default {
|
|||||||
|
|
||||||
yield put(routerRedux.replace('/'));
|
yield put(routerRedux.replace('/'));
|
||||||
|
|
||||||
debugger;
|
|
||||||
|
|
||||||
// Login successfully
|
// Login successfully
|
||||||
if (response.code === 0) {
|
if (response.code === 0) {
|
||||||
|
|
||||||
|
@ -3,7 +3,8 @@ import isEqual from 'lodash/isEqual';
|
|||||||
import { formatMessage } from 'umi/locale';
|
import { formatMessage } from 'umi/locale';
|
||||||
import Authorized from '@/utils/Authorized';
|
import Authorized from '@/utils/Authorized';
|
||||||
import { menu } from '../defaultSettings';
|
import { menu } from '../defaultSettings';
|
||||||
import { getAdminMenus, getAdminUrls } from '../services/admin';
|
import { getAdminUrls } from '../services/admin';
|
||||||
|
import { authorizationMenuResourceTree } from '../services/system';
|
||||||
|
|
||||||
const { check } = Authorized;
|
const { check } = Authorized;
|
||||||
|
|
||||||
@ -84,7 +85,7 @@ const findRootMenu = (antDataMenus, rootAntDataMenu, requestDataMenu) => {
|
|||||||
let res;
|
let res;
|
||||||
for (let i = 0; i < antDataMenus.length; i += 1) {
|
for (let i = 0; i < antDataMenus.length; i += 1) {
|
||||||
const antDataMenu = antDataMenus[i];
|
const antDataMenu = antDataMenus[i];
|
||||||
if (antDataMenu.path === requestDataMenu.handler) {
|
if (antDataMenu.path === requestDataMenu.route) {
|
||||||
res = rootAntDataMenu;
|
res = rootAntDataMenu;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -98,12 +99,12 @@ const findRootMenu = (antDataMenus, rootAntDataMenu, requestDataMenu) => {
|
|||||||
|
|
||||||
const buildTreeMenu = (antMenuData, moveChildrenMenusData, requestDataMenus) => {
|
const buildTreeMenu = (antMenuData, moveChildrenMenusData, requestDataMenus) => {
|
||||||
return requestDataMenus.map(item => {
|
return requestDataMenus.map(item => {
|
||||||
if (!item.handler) {
|
if (!item.route) {
|
||||||
// root 节点
|
// root 节点
|
||||||
const uuid = `sms${guid()}`;
|
const uuid = `sms${guid()}`;
|
||||||
const res = {
|
const res = {
|
||||||
icon: 'user',
|
icon: 'user',
|
||||||
name: item.displayName,
|
name: item.name,
|
||||||
path: uuid,
|
path: uuid,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -123,13 +124,13 @@ const buildTreeMenu = (antMenuData, moveChildrenMenusData, requestDataMenus) =>
|
|||||||
}
|
}
|
||||||
|
|
||||||
// moveChildrenMenusData 是一个 map,对比 url 地址是否存在,不存在就给一个 404 的页面
|
// moveChildrenMenusData 是一个 map,对比 url 地址是否存在,不存在就给一个 404 的页面
|
||||||
const handleMapperData = moveChildrenMenusData[item.handler];
|
const handleMapperData = moveChildrenMenusData[item.route];
|
||||||
if (handleMapperData) {
|
if (handleMapperData) {
|
||||||
return {
|
return {
|
||||||
...handleMapperData,
|
...handleMapperData,
|
||||||
icon: 'user',
|
icon: 'user',
|
||||||
name: item.displayName,
|
name: item.name,
|
||||||
path: item.handler,
|
path: item.route,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -191,7 +192,7 @@ export default {
|
|||||||
|
|
||||||
effects: {
|
effects: {
|
||||||
*getMenuData({ payload }, { put, call }) {
|
*getMenuData({ payload }, { put, call }) {
|
||||||
const { data } = yield call(getAdminMenus);
|
const { data } = yield call(authorizationMenuResourceTree);
|
||||||
const { routes, authority } = payload;
|
const { routes, authority } = payload;
|
||||||
|
|
||||||
// authority 已经不适用
|
// authority 已经不适用
|
||||||
|
@ -3,10 +3,6 @@ import request from '@/utils/request';
|
|||||||
|
|
||||||
// auth
|
// auth
|
||||||
|
|
||||||
export async function getAdminMenus() {
|
|
||||||
return request('/admin-api/admins/admin/menu_resource_tree');
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getAdminUrls(params) {
|
export async function getAdminUrls(params) {
|
||||||
return request(`/admin-api/admins/admin/url_resource_list?${stringify(params)}`);
|
return request(`/admin-api/admins/admin/url_resource_list?${stringify(params)}`);
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,19 @@
|
|||||||
import { stringify } from '@/utils/request.qs';
|
import { stringify } from '@/utils/request.qs';
|
||||||
import request from '@/utils/request';
|
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)}`, {
|
return request(`/system-api/admins/oauth2/username-authenticate?${stringify(params)}`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: {},
|
body: {},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ========== Authorization 模块 ==========
|
||||||
|
|
||||||
|
export async function authorizationMenuResourceTree() {
|
||||||
|
return request('/system-api/admins/authorization/menu-resource-tree', {
|
||||||
|
method: 'GET',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
package cn.iocoder.common.framework.mybatis;
|
package cn.iocoder.common.framework.mybatis;
|
||||||
|
|
||||||
|
import cn.iocoder.common.framework.util.CollectionUtil;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 拓展 MyBatis Plus QueryWrapper 类,主要增加如下功能:
|
* 拓展 MyBatis Plus QueryWrapper 类,主要增加如下功能:
|
||||||
*
|
*
|
||||||
@ -19,6 +22,20 @@ public class QueryWrapperX<T> extends QueryWrapper<T> {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public QueryWrapperX<T> inIfPresent(String column, Collection<?> values) {
|
||||||
|
if (!CollectionUtil.isEmpty(values)) {
|
||||||
|
return (QueryWrapperX<T>) super.in(column, values);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public QueryWrapperX<T> inIfPresent(String column, Object... values) {
|
||||||
|
if (!CollectionUtil.isEmpty(values)) {
|
||||||
|
return (QueryWrapperX<T>) super.in(column, values);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public QueryWrapperX<T> eqIfPresent(String column, Object val) {
|
public QueryWrapperX<T> eqIfPresent(String column, Object val) {
|
||||||
if (val != null) {
|
if (val != null) {
|
||||||
return (QueryWrapperX<T>) super.eq(column, val);
|
return (QueryWrapperX<T>) super.eq(column, val);
|
||||||
|
@ -14,5 +14,9 @@ public class AdminSecurityContext {
|
|||||||
* 管理员编号
|
* 管理员编号
|
||||||
*/
|
*/
|
||||||
private Integer adminId;
|
private Integer adminId;
|
||||||
|
/**
|
||||||
|
* 账号编号
|
||||||
|
*/
|
||||||
|
private Integer accountId;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -27,4 +27,12 @@ public class AdminSecurityContextHolder {
|
|||||||
SECURITY_CONTEXT.remove();
|
SECURITY_CONTEXT.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Integer getAdminId() {
|
||||||
|
return getContext().getAdminId();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Integer getAccountId() {
|
||||||
|
return getContext().getAccountId();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -6,12 +6,15 @@ import cn.iocoder.mall.security.core.context.AdminSecurityContext;
|
|||||||
import cn.iocoder.mall.security.core.context.AdminSecurityContextHolder;
|
import cn.iocoder.mall.security.core.context.AdminSecurityContextHolder;
|
||||||
import cn.iocoder.mall.system.rpc.api.admin.AdminRPC;
|
import cn.iocoder.mall.system.rpc.api.admin.AdminRPC;
|
||||||
import cn.iocoder.mall.system.rpc.response.admin.AdminResponse;
|
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.apache.dubbo.config.annotation.Reference;
|
||||||
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
|
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import static cn.iocoder.mall.system.biz.enums.SystemErrorCodeEnum.ADMIN_NOT_FOUND;
|
||||||
|
|
||||||
public class AdminSecurityInterceptor extends HandlerInterceptorAdapter {
|
public class AdminSecurityInterceptor extends HandlerInterceptorAdapter {
|
||||||
|
|
||||||
@Reference(validation = "true", version = "${dubbo.consumer.AdminRPC.version}")
|
@Reference(validation = "true", version = "${dubbo.consumer.AdminRPC.version}")
|
||||||
@ -19,16 +22,20 @@ public class AdminSecurityInterceptor extends HandlerInterceptorAdapter {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
|
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
|
||||||
Integer accountId = AdminSecurityContextHolder.getContext().getAdminId();
|
Integer accountId = CommonWebUtil.getAccountId(request);
|
||||||
if (accountId != null) {
|
if (accountId != null) {
|
||||||
// 获得 Admin 信息
|
// 获得 Admin 信息
|
||||||
CommonResult<AdminResponse> adminResult = adminRPC.getAdminByAccountId(accountId);
|
CommonResult<AdminResponse> adminResult = adminRPC.getAdminByAccountId(accountId);
|
||||||
if (adminResult.isError()) {
|
if (adminResult.isError()) {
|
||||||
throw ServiceExceptionUtil.exception(adminResult);
|
throw ServiceExceptionUtil.exception(adminResult);
|
||||||
}
|
}
|
||||||
|
if (adminResult.getData() == null) {
|
||||||
|
throw ServiceExceptionUtil.exception(ADMIN_NOT_FOUND);
|
||||||
|
}
|
||||||
// 设置到 SecurityContext 中
|
// 设置到 SecurityContext 中
|
||||||
AdminResponse adminResponse = adminResult.getData();
|
AdminResponse adminResponse = adminResult.getData();
|
||||||
AdminSecurityContext context = new AdminSecurityContext().setAdminId(adminResponse.getId());
|
AdminSecurityContext context = new AdminSecurityContext().setAdminId(adminResponse.getId())
|
||||||
|
.setAccountId(accountId);
|
||||||
AdminSecurityContextHolder.setContext(context);
|
AdminSecurityContextHolder.setContext(context);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
package cn.iocoder.mall.security.core.interceptor;
|
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.util.ServiceExceptionUtil;
|
||||||
import cn.iocoder.common.framework.vo.CommonResult;
|
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.UserSecurityContext;
|
||||||
import cn.iocoder.mall.security.core.context.UserSecurityContextHolder;
|
import cn.iocoder.mall.security.core.context.UserSecurityContextHolder;
|
||||||
import cn.iocoder.mall.system.rpc.api.user.UserRPC;
|
import cn.iocoder.mall.system.rpc.api.user.UserRPC;
|
||||||
import cn.iocoder.mall.system.rpc.response.user.UserResponse;
|
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.apache.dubbo.config.annotation.Reference;
|
||||||
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
|
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
|
||||||
|
|
||||||
@ -20,13 +21,16 @@ public class UserSecurityInterceptor extends HandlerInterceptorAdapter {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
|
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
|
||||||
Integer accountId = AdminSecurityContextHolder.getContext().getAdminId();
|
Integer accountId = CommonWebUtil.getAccountId(request);
|
||||||
if (accountId != null) {
|
if (accountId != null) {
|
||||||
// 获得 Admin 信息
|
// 获得 Admin 信息
|
||||||
CommonResult<UserResponse> userResult = userRPC.getUserByAccountId(accountId);
|
CommonResult<UserResponse> userResult = userRPC.getUserByAccountId(accountId);
|
||||||
if (userResult.isError()) {
|
if (userResult.isError()) {
|
||||||
throw ServiceExceptionUtil.exception(userResult);
|
throw ServiceExceptionUtil.exception(userResult);
|
||||||
}
|
}
|
||||||
|
if (userResult.getData() == null) {
|
||||||
|
throw ExceptionUtil.getServiceException(null); // TODO 需要完善
|
||||||
|
}
|
||||||
// 设置到 SecurityContext 中
|
// 设置到 SecurityContext 中
|
||||||
UserResponse userResponse = userResult.getData();
|
UserResponse userResponse = userResult.getData();
|
||||||
UserSecurityContext context = new UserSecurityContext().setUserId(userResponse.getId());
|
UserSecurityContext context = new UserSecurityContext().setUserId(userResponse.getId());
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -4,20 +4,14 @@ import cn.iocoder.common.framework.mybatis.QueryWrapperX;
|
|||||||
import cn.iocoder.mall.system.biz.dataobject.authorization.ResourceDO;
|
import cn.iocoder.mall.system.biz.dataobject.authorization.ResourceDO;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
import org.apache.ibatis.annotations.Param;
|
|
||||||
import org.springframework.stereotype.Repository;
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
@Repository
|
@Repository
|
||||||
public interface ResourceMapper extends BaseMapper<ResourceDO> {
|
public interface ResourceMapper extends BaseMapper<ResourceDO> {
|
||||||
|
|
||||||
// TODO 芋艿,后续改造。
|
|
||||||
List<ResourceDO> selectListByTypeAndRoleIds(@Param("type") Integer type,
|
|
||||||
@Param("roleIds") Set<Integer> roleIds);
|
|
||||||
|
|
||||||
default ResourceDO selectByPermission(String permission) {
|
default ResourceDO selectByPermission(String permission) {
|
||||||
return selectOne(new QueryWrapper<ResourceDO>().eq("permission", permission));
|
return selectOne(new QueryWrapper<ResourceDO>().eq("permission", permission));
|
||||||
}
|
}
|
||||||
@ -26,8 +20,9 @@ public interface ResourceMapper extends BaseMapper<ResourceDO> {
|
|||||||
return selectList(new QueryWrapper<ResourceDO>().in("permission", permissions));
|
return selectList(new QueryWrapper<ResourceDO>().in("permission", permissions));
|
||||||
}
|
}
|
||||||
|
|
||||||
default List<ResourceDO> selectListByType(Integer type) {
|
default List<ResourceDO> selectListByIdsAndType(Collection<Integer> ids, Integer type) {
|
||||||
return selectList(new QueryWrapperX<ResourceDO>().eqIfPresent("type", type));
|
return selectList(new QueryWrapperX<ResourceDO>().inIfPresent("id", ids)
|
||||||
|
.eqIfPresent("type", type));
|
||||||
}
|
}
|
||||||
|
|
||||||
default int selectCountByPid(Integer pid) {
|
default int selectCountByPid(Integer pid) {
|
||||||
|
@ -27,6 +27,14 @@ public interface RoleResourceMapper extends BaseMapper<RoleResourceDO> {
|
|||||||
return selectList(new QueryWrapper<RoleResourceDO>().in("resource_id", resourceIds));
|
return selectList(new QueryWrapper<RoleResourceDO>().in("resource_id", resourceIds));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default List<RoleResourceDO> selectListByRoleId(Integer roleId) {
|
||||||
|
return selectList(new QueryWrapper<RoleResourceDO>().eq("role_id", roleId));
|
||||||
|
}
|
||||||
|
|
||||||
|
default List<RoleResourceDO> selectListByRoleIds(Collection<Integer> roleIds) {
|
||||||
|
return selectList(new QueryWrapper<RoleResourceDO>().in("role_id", roleIds));
|
||||||
|
}
|
||||||
|
|
||||||
default int deleteByResourceId(Integer resourceId) {
|
default int deleteByResourceId(Integer resourceId) {
|
||||||
return delete(new QueryWrapper<RoleResourceDO>().eq("resource_id", resourceId));
|
return delete(new QueryWrapper<RoleResourceDO>().eq("resource_id", resourceId));
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
}
|
@ -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<Integer> ids;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 资源类型
|
||||||
|
*/
|
||||||
|
private Integer type;
|
||||||
|
|
||||||
|
}
|
@ -1,9 +1,32 @@
|
|||||||
package cn.iocoder.mall.system.biz.service.authorization;
|
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.AuthorizationCheckPermissionsDTO;
|
||||||
|
import cn.iocoder.mall.system.biz.dto.authorization.AuthorizationGetResourcesByAccountIdDTO;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 授权模块 - Service 接口
|
||||||
|
*/
|
||||||
public interface AuthorizationService {
|
public interface AuthorizationService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验指定账号是否有指定权限。如果没有,则抛出 {@link ServiceException} 异常
|
||||||
|
*
|
||||||
|
* @param checkPermissionsDTO 校验权限 DTO
|
||||||
|
*/
|
||||||
void checkPermissions(AuthorizationCheckPermissionsDTO checkPermissionsDTO);
|
void checkPermissions(AuthorizationCheckPermissionsDTO checkPermissionsDTO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得指定账号的资源列表
|
||||||
|
*
|
||||||
|
* 如果该账号为超级管理员,则返回所有资源
|
||||||
|
*
|
||||||
|
* @param getResourcesByAccountIdDTO 查询条件 DTO
|
||||||
|
* @return 列表
|
||||||
|
*/
|
||||||
|
List<ResourceBO> getResourcesByAccountId(AuthorizationGetResourcesByAccountIdDTO getResourcesByAccountIdDTO);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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.AccountRoleDO;
|
||||||
import cn.iocoder.mall.system.biz.dataobject.authorization.RoleResourceDO;
|
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.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 lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import static cn.iocoder.mall.system.biz.enums.SystemErrorCodeEnum.AUTHORIZATION_PERMISSION_DENY;
|
import static cn.iocoder.mall.system.biz.enums.SystemErrorCodeEnum.AUTHORIZATION_PERMISSION_DENY;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 授权模块 - Service 实现类
|
||||||
|
*/
|
||||||
@Service
|
@Service
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class AuthorizationServiceImpl implements AuthorizationService {
|
public class AuthorizationServiceImpl implements AuthorizationService {
|
||||||
@ -45,7 +51,7 @@ public class AuthorizationServiceImpl implements AuthorizationService {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 查询权限对应资源
|
// 查询权限对应资源
|
||||||
List<ResourceBO> resourceBOs = resourceService.getListByPermissions(checkPermissionsDTO.getPermissions());
|
List<ResourceBO> resourceBOs = resourceService.getResourcesByPermissions(checkPermissionsDTO.getPermissions());
|
||||||
if (CollectionUtil.isEmpty(resourceBOs)) { // 无对应资源,则认为无需权限验证
|
if (CollectionUtil.isEmpty(resourceBOs)) { // 无对应资源,则认为无需权限验证
|
||||||
log.warn("[checkPermissions][permission({}) 未配置对应资源]", checkPermissionsDTO.getPermissions());
|
log.warn("[checkPermissions][permission({}) 未配置对应资源]", checkPermissionsDTO.getPermissions());
|
||||||
return;
|
return;
|
||||||
@ -65,4 +71,26 @@ public class AuthorizationServiceImpl implements AuthorizationService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ResourceBO> getResourcesByAccountId(AuthorizationGetResourcesByAccountIdDTO getResourcesByAccountIdDTO) {
|
||||||
|
// 查询管理员拥有的角色关联数据
|
||||||
|
List<AccountRoleDO> accountRoleDOs = accountRoleMapper.selectByAccountId(getResourcesByAccountIdDTO.getAccountId());
|
||||||
|
if (CollectionUtil.isEmpty(accountRoleDOs)) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
Set<Integer> roleIds = CollectionUtil.convertSet(accountRoleDOs, AccountRoleDO::getRoleId);
|
||||||
|
// 判断是否为超管。若是超管,默认有所有权限
|
||||||
|
if (roleService.hasSuperAdmin(roleIds)) {
|
||||||
|
return resourceService.getResources(new ResourceGetListDTO().setType(getResourcesByAccountIdDTO.getType()));
|
||||||
|
}
|
||||||
|
// 查询角色拥有的资源关联数据
|
||||||
|
List<RoleResourceDO> roleResourceDOs = roleResourceMapper.selectListByRoleIds(roleIds);
|
||||||
|
if (CollectionUtil.isEmpty(roleResourceDOs)) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
Set<Integer> resourceIds = CollectionUtil.convertSet(roleResourceDOs, RoleResourceDO::getResourceId);
|
||||||
|
// 查询对应资源
|
||||||
|
return resourceService.getResources(new ResourceGetListDTO().setIds(resourceIds).setType(getResourcesByAccountIdDTO.getType()));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
package cn.iocoder.mall.system.biz.service.authorization;
|
package cn.iocoder.mall.system.biz.service.authorization;
|
||||||
|
|
||||||
import cn.iocoder.mall.system.biz.bo.authorization.ResourceBO;
|
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.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public interface ResourceService {
|
public interface ResourceService {
|
||||||
|
|
||||||
List<ResourceBO> getListByPermissions(Collection<String> permissions);
|
List<ResourceBO> getResourcesByPermissions(Collection<String> permissions);
|
||||||
|
|
||||||
|
List<ResourceBO> getResources(ResourceGetListDTO getListDTO);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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.convert.authorization.ResourceConvert;
|
||||||
import cn.iocoder.mall.system.biz.dao.authorization.ResourceMapper;
|
import cn.iocoder.mall.system.biz.dao.authorization.ResourceMapper;
|
||||||
import cn.iocoder.mall.system.biz.dataobject.authorization.ResourceDO;
|
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.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
@ -17,9 +18,15 @@ public class ResourceServiceImpl implements ResourceService {
|
|||||||
private ResourceMapper resourceMapper;
|
private ResourceMapper resourceMapper;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<ResourceBO> getListByPermissions(Collection<String> permissions) {
|
public List<ResourceBO> getResourcesByPermissions(Collection<String> permissions) {
|
||||||
List<ResourceDO> resourceDOs = resourceMapper.selectListByPermissions(permissions);
|
List<ResourceDO> resourceDOs = resourceMapper.selectListByPermissions(permissions);
|
||||||
return ResourceConvert.INSTANCE.convertList(resourceDOs);
|
return ResourceConvert.INSTANCE.convertList(resourceDOs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ResourceBO> getResources(ResourceGetListDTO getListDTO) {
|
||||||
|
List<ResourceDO> resourceDOs = resourceMapper.selectListByIdsAndType(getListDTO.getIds(), getListDTO.getType());
|
||||||
|
return ResourceConvert.INSTANCE.convertList(resourceDOs);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,27 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
|
||||||
<mapper namespace="cn.iocoder.mall.admin.dao.ResourceMapper">
|
|
||||||
|
|
||||||
<sql id="FIELDS">
|
|
||||||
id, type, sort, display_name, icon, permissions,
|
|
||||||
create_time, pid, handler
|
|
||||||
</sql>
|
|
||||||
|
|
||||||
<select id="selectListByTypeAndRoleIds" resultType="ResourceDO">
|
|
||||||
SELECT
|
|
||||||
r.id, r.type, r.sort, r.display_name,
|
|
||||||
r.create_time, r.pid, r.handler
|
|
||||||
FROM resource r, role_resource rr
|
|
||||||
WHERE r.deleted = 0
|
|
||||||
AND rr.deleted = 0
|
|
||||||
<if test="type != null">
|
|
||||||
AND r.type = #{type}
|
|
||||||
</if>
|
|
||||||
AND rr.role_id IN
|
|
||||||
<foreach item="roleId" collection="roleIds" separator="," open="(" close=")" index="">
|
|
||||||
#{roleId}
|
|
||||||
</foreach>
|
|
||||||
AND r.id = rr.resource_id
|
|
||||||
</select>
|
|
||||||
|
|
||||||
</mapper>
|
|
@ -8,7 +8,7 @@ import org.springframework.web.bind.annotation.RestController;
|
|||||||
@RestController
|
@RestController
|
||||||
@RequestMapping(MallConstants.ROOT_PATH_ADMIN + "/admin")
|
@RequestMapping(MallConstants.ROOT_PATH_ADMIN + "/admin")
|
||||||
@Api(tags = "管理员 - 管理员 API")
|
@Api(tags = "管理员 - 管理员 API")
|
||||||
public class AdminsOAdminController {
|
public class AdminsAdminController {
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -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<List<AdminsAuthorizationMenuTreeResponse>> menuResourceTree() {
|
||||||
|
List<ResourceBO> resources = authorizationService.getResourcesByAccountId(new AuthorizationGetResourcesByAccountIdDTO()
|
||||||
|
.setAccountId(AdminSecurityContextHolder.getAccountId()).setType(ResourceTypeEnum.MENU.getValue()));
|
||||||
|
// 创建 AdminMenuTreeNodeVO Map
|
||||||
|
// 使用 LinkedHashMap 的原因,是为了排序 。实际也可以用 Stream API ,就是太丑了。
|
||||||
|
Map<Integer, AdminsAuthorizationMenuTreeResponse> 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<AdminsAuthorizationMenuTreeResponse> rootNodes = treeNodeMap.values().stream()
|
||||||
|
.filter(node -> node.getPid().equals(ResourceIdEnum.ROOT.getId()))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
return CommonResult.success(rootNodes);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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);
|
||||||
|
|
||||||
|
}
|
@ -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.ApiModel;
|
||||||
import io.swagger.annotations.ApiModelProperty;
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
@ -7,24 +7,23 @@ import lombok.experimental.Accessors;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ApiModel("管理员拥有的菜单 VO")
|
@ApiModel("管理员 - 授权模块 - 菜单资源树")
|
||||||
@Data
|
@Data
|
||||||
@Accessors(chain = true)
|
@Accessors(chain = true)
|
||||||
public class AdminMenuTreeNodeVO {
|
public class AdminsAuthorizationMenuTreeResponse {
|
||||||
|
|
||||||
@ApiModelProperty(value = "菜单编号", required = true, example = "1")
|
@ApiModelProperty(value = "菜单编号", required = true, example = "1")
|
||||||
private Integer id;
|
private Integer id;
|
||||||
// @ApiModelProperty(value = "菜单名", required = true, example = "商品管理")
|
@ApiModelProperty(value = "菜单名", required = true, example = "商品管理")
|
||||||
// private String name;
|
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 = "1")
|
@ApiModelProperty(value = "排序", required = true, example = "1")
|
||||||
private Integer sort;
|
private Integer sort;
|
||||||
@ApiModelProperty(value = "菜单展示名", required = true, example = "商品管理")
|
@ApiModelProperty(value = "父菜单编号", required = true, example = "1", notes = "如果无父菜单,则值为 0")
|
||||||
private String displayName;
|
private Integer pid;
|
||||||
|
@ApiModelProperty(value = "route", required = true, example = "/order/list")
|
||||||
|
private String route;
|
||||||
@ApiModelProperty(value = "子节点数组")
|
@ApiModelProperty(value = "子节点数组")
|
||||||
private List<AdminMenuTreeNodeVO> children;
|
private List<AdminsAuthorizationMenuTreeResponse> children;
|
||||||
|
|
||||||
}
|
}
|
@ -54,35 +54,6 @@ public class AdminController {
|
|||||||
|
|
||||||
// TODO 功能:当前管理员
|
// TODO 功能:当前管理员
|
||||||
|
|
||||||
@SuppressWarnings("Duplicates")
|
|
||||||
@GetMapping("/menu_resource_tree")
|
|
||||||
@ApiOperation(value = "获得当前登陆的管理员拥有的菜单权限", notes = "以树结构返回")
|
|
||||||
public CommonResult<List<AdminMenuTreeNodeVO>> menuResourceTree() {
|
|
||||||
List<ResourceBO> resources = resourceService.getResourcesByTypeAndRoleIds(ResourceConstants.TYPE_MENU,
|
|
||||||
AdminSecurityContextHolder.getContext().getRoleIds());
|
|
||||||
// 创建 AdminMenuTreeNodeVO Map
|
|
||||||
Map<Integer, AdminMenuTreeNodeVO> 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<AdminMenuTreeNodeVO> 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")
|
@GetMapping("/url_resource_list")
|
||||||
@ApiOperation(value = "获得当前登陆的管理员拥有的 URL 权限列表")
|
@ApiOperation(value = "获得当前登陆的管理员拥有的 URL 权限列表")
|
||||||
public CommonResult<Set<String>> urlResourceList() {
|
public CommonResult<Set<String>> urlResourceList() {
|
||||||
|
Loading…
Reference in New Issue
Block a user