1. 迁移角色相关逻辑

2. admin-web 接入角色新接口
This commit is contained in:
YunaiV 2020-04-29 00:42:33 +08:00
parent 4e5b6ff2cf
commit 0763551d6d
16 changed files with 174 additions and 126 deletions

View File

@ -2,13 +2,16 @@ import { message } from 'antd';
import { arrayToStringParams } from '../../utils/request.qs';
import { buildTreeNode, findAllNodes, findCheckedKeys } from '../../utils/tree.utils';
import {
addRole,
updateRole,
deleteRole,
queryRole,
queryRoleResourceTree,
roleAssignResource,
} from '../../services/admin';
import {
rolePage,
roleAdd,
roleUpdate,
roleDelete,
} from '../../services/system';
export default {
namespace: 'roleList',
@ -27,7 +30,7 @@ export default {
effects: {
*add({ payload }, { call, put }) {
const { callback, body, queryParams } = payload;
const response = yield call(addRole, body);
const response = yield call(roleAdd, body);
if (callback) {
callback(response);
}
@ -40,7 +43,7 @@ export default {
},
*update({ payload }, { call, put }) {
const { callback, body, queryParams } = payload;
const response = yield call(updateRole, body);
const response = yield call(roleUpdate, body);
if (callback) {
callback(response);
}
@ -53,7 +56,7 @@ export default {
},
*delete({ payload }, { call, put }) {
const { queryParams, body } = payload;
yield call(deleteRole, body);
yield call(roleDelete, body);
message.info('删除成功!');
yield put({
type: 'query',
@ -63,7 +66,7 @@ export default {
});
},
*query({ payload }, { call, put }) {
const response = yield call(queryRole, payload);
const response = yield call(rolePage, payload);
message.info('查询成功!');
const { total, list } = response.data;
yield put({

View File

@ -44,6 +44,12 @@ const CreateForm = Form.create()(props => {
initialValue: initValues.name,
})(<Input placeholder="请输入" />)}
</FormItem>
<FormItem labelCol={{ span: 5 }} wrapperCol={{ span: 15 }} label="角色编码">
{form.getFieldDecorator('code', {
rules: [{ required: false }],
initialValue: initValues.code,
})(<Input placeholder="请输入" />)}
</FormItem>
</Modal>
);
});
@ -286,6 +292,10 @@ class RoleList extends PureComponent {
title: '名称',
dataIndex: 'name',
},
{
title: '编码',
dataIndex: 'code',
},
{
title: '创建时间',
dataIndex: 'createTime',

View File

@ -88,30 +88,7 @@ export async function deptTreeAll() {
// role
export async function queryRole(params) {
return request(`/admin-api/admins/role/page?${stringify(params)}`);
}
export async function deleteRole(params) {
return request(`/admin-api/admins/role/delete?${stringify(params)}`, {
method: 'POST',
body: {},
});
}
export async function addRole(params) {
return request(`/admin-api/admins/role/add?${stringify(params)}`, {
method: 'POST',
body: {},
});
}
export async function updateRole(params) {
return request(`/admin-api/admins/role/update?${stringify(params)}`, {
method: 'POST',
body: {},
});
}
export async function queryRoleResourceTree(params) {
return request(`/admin-api/admins/role/resource_tree?${stringify(params)}`, {

View File

@ -49,3 +49,30 @@ export async function resourceDelete(params) {
method: 'POST',
});
}
// ========== Role 模块 ==========
export async function rolePage(params) {
return request(`/system-api/admins/role/page?${stringify(params)}`);
}
export async function roleDelete(params) {
return request(`/system-api/admins/role/delete?${stringify(params)}`, {
method: 'POST',
body: {},
});
}
export async function roleAdd(params) {
return request(`/system-api/admins/role/add?${stringify(params)}`, {
method: 'POST',
body: {},
});
}
export async function roleUpdate(params) {
return request(`/system-api/admins/role/update?${stringify(params)}`, {
method: 'POST',
body: {},
});
}

View File

@ -4,7 +4,7 @@ import lombok.Data;
import lombok.experimental.Accessors;
/**
* 账号信息 BO
* 账号模块 - 账号信息 BO
*/
@Data
@Accessors(chain = true)

View File

@ -0,0 +1,18 @@
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 AuthorizationGetRoleResourcesDTO {
@NotNull(message = "角色编号不能为空")
private Integer roleId;
}

View File

@ -4,7 +4,7 @@ import cn.iocoder.mall.system.biz.bo.account.AccountBO;
import cn.iocoder.mall.system.biz.dto.account.AccountCreateDTO;
/**
* 账号 Service 接口
* 账号模块 - Service 接口
*/
public interface AccountService {

View File

@ -5,8 +5,10 @@ import cn.iocoder.mall.system.biz.bo.authorization.ResourceBO;
import cn.iocoder.mall.system.biz.bo.authorization.ResourceTreeNodeBO;
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.AuthorizationGetRoleResourcesDTO;
import java.util.List;
import java.util.Set;
/**
* 授权模块 - Service 接口
@ -40,4 +42,12 @@ public interface AuthorizationService {
*/
List<ResourceTreeNodeBO> getResourceTreeByAccountId(AuthorizationGetResourcesByAccountIdDTO getResourceTreeByAccountIdDTO);
/**
* 获得指定角色拥有的资源编号集合
*
* @param getRoleResourcesDTO 查询条件 DTO
* @return 资源编号数集合
*/
Set<Integer> getRoleResources(AuthorizationGetRoleResourcesDTO getRoleResourcesDTO);
}

View File

@ -8,20 +8,14 @@ import cn.iocoder.mall.system.biz.dao.authorization.AccountRoleMapper;
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 cn.iocoder.mall.system.biz.dto.authorization.ResourceGetTreeDTO;
import cn.iocoder.mall.system.biz.dto.authorization.*;
import cn.iocoder.mall.system.biz.event.authorization.ResourceDeleteEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.*;
import static cn.iocoder.mall.system.biz.enums.SystemErrorCodeEnum.AUTHORIZATION_PERMISSION_DENY;
@ -119,6 +113,21 @@ public class AuthorizationServiceImpl implements AuthorizationService {
return resourceService.getResourceTree(new ResourceGetTreeDTO().setIds(resourceIds).setType(getResourcesByAccountIdDTO.getType()));
}
@Override
public Set<Integer> getRoleResources(AuthorizationGetRoleResourcesDTO getRoleResourcesDTO) {
Set<Integer> roleIds = Collections.singleton(getRoleResourcesDTO.getRoleId());
// 判断是否为超管若是超管默认有所有权限
if (roleService.hasSuperAdmin(roleIds)) {
return CollectionUtil.convertSet(resourceService.getResources(new ResourceGetListDTO()), ResourceBO::getId);
}
// 查询角色拥有的资源关联数据
List<RoleResourceDO> roleResourceDOs = roleResourceMapper.selectListByRoleIds(roleIds);
if (CollectionUtil.isEmpty(roleResourceDOs)) {
return Collections.emptySet();
}
return CollectionUtil.convertSet(roleResourceDOs, RoleResourceDO::getResourceId);
}
@EventListener
public void handleResourceDeleteEvent(ResourceDeleteEvent event) {
roleResourceMapper.deleteByResourceId(event.getId());

View File

@ -17,6 +17,12 @@ public interface ResourceService {
List<ResourceBO> getResources(ResourceGetListDTO getListDTO);
/**
* 获得资源树
*
* @param getTreeDTO 查询条件
* @return 资源树
*/
List<ResourceTreeNodeBO> getResourceTree(ResourceGetTreeDTO getTreeDTO);
Integer addResource(ResourceAddDTO addDTO);

View File

@ -6,16 +6,22 @@ import cn.iocoder.mall.security.core.context.AdminSecurityContextHolder;
import cn.iocoder.mall.system.biz.bo.authorization.ResourceBO;
import cn.iocoder.mall.system.biz.bo.authorization.ResourceTreeNodeBO;
import cn.iocoder.mall.system.biz.dto.authorization.AuthorizationGetResourcesByAccountIdDTO;
import cn.iocoder.mall.system.biz.dto.authorization.AuthorizationGetRoleResourcesDTO;
import cn.iocoder.mall.system.biz.dto.authorization.ResourceGetTreeDTO;
import cn.iocoder.mall.system.biz.enums.authorization.ResourceTypeEnum;
import cn.iocoder.mall.system.biz.service.authorization.AuthorizationService;
import cn.iocoder.mall.system.biz.service.authorization.ResourceService;
import cn.iocoder.mall.system.rest.convert.authorization.AdminsAuthorizationConvert;
import cn.iocoder.mall.system.rest.response.authorization.AdminsAuthorizationMenuTreeResponse;
import cn.iocoder.mall.system.rest.response.authorization.AdminsAuthorizationRoleResourceTreeResponse;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
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.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@ -30,6 +36,8 @@ public class AdminsAuthorizationController {
@Autowired
private AuthorizationService authorizationService;
@Autowired
private ResourceService resourceService;
@GetMapping("/menu-resource-tree")
@ApiOperation(value = "获得当前账号的菜单资源树", notes = "以树结构返回")
@ -47,4 +55,16 @@ public class AdminsAuthorizationController {
return CommonResult.success(resources.stream().map(ResourceBO::getRoute).collect(Collectors.toSet()));
}
@GetMapping("/role_tree")
@ApiOperation(value = "获得角色拥有的菜单权限", notes = "以树结构返回。注意,返回的资源树是完整的结构,会标记每个资源节点是否被角色所拥有")
@ApiImplicitParam(name = "roleId", value = "角色编号", required = true, example = "1")
public CommonResult<List<AdminsAuthorizationRoleResourceTreeResponse>> roleTree(@RequestParam("roleId") Integer roleId) {
// 1. 获得完整的资源树
List<ResourceTreeNodeBO> resourceTreeNodeBOs = resourceService.getResourceTree(new ResourceGetTreeDTO());
// 2. 获得角色拥有的子树
Set<Integer> roleResourceIds = authorizationService.getRoleResources(new AuthorizationGetRoleResourcesDTO().setRoleId(roleId));
// 3. 拼接返回结果
return CommonResult.success(AdminsAuthorizationConvert.INSTANCE.convertList(resourceTreeNodeBOs, roleResourceIds));
}
}

View File

@ -69,40 +69,7 @@ public class AdminsRoleController {
return CommonResult.success(true);
}
// @GetMapping("/role_tree")
// @ApiOperation(value = "获得角色拥有的菜单权限", notes = "以树结构返回")
// @ApiImplicitParam(name = "id", value = "角色编号", required = true, example = "1")
// public CommonResult<List<RoleRoleTreeNodeVO>> roleTree(@RequestParam("id") Integer id) {
// // 芋艿此处严格来说可以在校验下角色是否存在不过呢校验了也没啥意义因为一般不存在这个情况且不会有业务上的影响并且反倒多了一次 rpc 调用
// // 第一步获得角色拥有的资源数组
// Set<Integer> roleRoles = roleService.getRolesByTypeAndRoleIds(null, CollectionUtil.asSet(id))
// .stream().map(RoleBO::getId).collect(Collectors.toSet());
// // 第二步获得资源树
// List<RoleBO> allRoles = roleService.getRolesByType(null);
// // 创建 AdminMenuTreeNodeVO Map
// Map<Integer, RoleRoleTreeNodeVO> treeNodeMap = allRoles.stream().collect(Collectors.toMap(RoleBO::getId, RoleConvert.INSTANCE::convert4));
// // 处理父子关系
// treeNodeMap.values().stream()
// .filter(node -> !node.getPid().equals(RoleConstants.PID_ROOT))
// .forEach((childNode) -> {
// // 获得父节点
// RoleRoleTreeNodeVO parentNode = treeNodeMap.get(childNode.getPid());
// if (parentNode.getChildren() == null) { // 初始化 children 数组
// parentNode.setChildren(new ArrayList<>());
// }
// // 将自己添加到父节点中
// parentNode.getChildren().add(childNode);
// });
// // 获得到所有的根节点
// List<RoleRoleTreeNodeVO> rootNodes = treeNodeMap.values().stream()
// .filter(node -> node.getPid().equals(RoleConstants.PID_ROOT))
// .sorted(Comparator.comparing(RoleRoleTreeNodeVO::getSort))
// .collect(Collectors.toList());
// // 第三步设置角色是否有该角色
// treeNodeMap.values().forEach(nodeVO -> nodeVO.setAssigned(roleRoles.contains(nodeVO.getId())));
// // 返回结果
// return success(rootNodes);
// }
//
// @PostMapping("/assign_role")
// @ApiOperation(value = "分配角色资源")

View File

@ -3,11 +3,14 @@ package cn.iocoder.mall.system.rest.convert.authorization;
import cn.iocoder.mall.system.biz.bo.authorization.ResourceBO;
import cn.iocoder.mall.system.biz.bo.authorization.ResourceTreeNodeBO;
import cn.iocoder.mall.system.rest.response.authorization.AdminsAuthorizationMenuTreeResponse;
import cn.iocoder.mall.system.rest.response.authorization.AdminsAuthorizationRoleResourceTreeResponse;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
@Mapper
public interface AdminsAuthorizationConvert {
@ -22,6 +25,25 @@ public interface AdminsAuthorizationConvert {
@Mapping(source = "node.icon", target = "icon")
AdminsAuthorizationMenuTreeResponse convert(ResourceTreeNodeBO bean);
@Mapping(source = "node.id", target = "id")
@Mapping(source = "node.name", target = "name")
AdminsAuthorizationRoleResourceTreeResponse convert2(ResourceTreeNodeBO bean);
List<AdminsAuthorizationMenuTreeResponse> convertList(List<ResourceTreeNodeBO> beans);
default List<AdminsAuthorizationRoleResourceTreeResponse> convertList(List<ResourceTreeNodeBO> beans, Set<Integer> roleResourceIds) {
List<AdminsAuthorizationRoleResourceTreeResponse> responses = new ArrayList<>(beans.size());
for (ResourceTreeNodeBO bean : beans) {
// 转换
AdminsAuthorizationRoleResourceTreeResponse response = this.convert2(bean);
response.setAssign(roleResourceIds.contains(bean.getNode().getId()));
// 递归子节点
this.convertList(bean.getChildren(), roleResourceIds);
// 添加到结果
responses.add(response);
}
return responses;
}
}

View File

@ -7,7 +7,7 @@ import lombok.experimental.Accessors;
import java.util.List;
@ApiModel("管理员 - 授权模块 - 菜单资源")
@ApiModel(value = "管理员 - 授权模块 - 菜单资源", description = "一般用于首页菜单")
@Data
@Accessors(chain = true)
public class AdminsAuthorizationMenuTreeResponse {
@ -20,7 +20,9 @@ public class AdminsAuthorizationMenuTreeResponse {
private String route;
@ApiModelProperty(value = "菜单图标", required = true, example = "user")
private String icon;
@ApiModelProperty(value = "子节点数组")
/**
* 子节点数组
*/
private List<AdminsAuthorizationMenuTreeResponse> children;
}

View File

@ -0,0 +1,26 @@
package cn.iocoder.mall.system.rest.response.authorization;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.List;
@ApiModel(value = "管理员 - 授权模块 - 角色拥有的资源树")
@Data
@Accessors(chain = true)
public class AdminsAuthorizationRoleResourceTreeResponse {
@ApiModelProperty(value = "菜单编号", required = true, example = "1")
private Integer id;
@ApiModelProperty(value = "菜单名", required = true, example = "商品管理")
private String name;
@ApiModelProperty(value = "是否分配", required = true, notes = "即角色是否拥有该资源")
private Boolean assign;
/**
* 子节点数组
*/
private List<AdminsAuthorizationRoleResourceTreeResponse> children;
}

View File

@ -1,49 +0,0 @@
package cn.iocoder.mall.system.application.controller.admins;
import cn.iocoder.common.framework.vo.CommonResult;
import cn.iocoder.mall.system.api.AdminService;
import cn.iocoder.mall.system.api.OAuth2Service;
import cn.iocoder.mall.system.api.bo.admin.AdminAuthenticationBO;
import cn.iocoder.mall.system.api.dto.admin.AdminAuthenticationDTO;
import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.Metrics;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import static cn.iocoder.common.framework.vo.CommonResult.success;
@RestController
@RequestMapping("admins/passport")
@Api("Admin Passport 模块")
@Deprecated
public class PassportController {
/**
* 登陆总数 Metrics
*/
private static final Counter METRICS_LOGIN_TOTAL = Metrics.counter("mall.admin.passport.login.total");
@Reference(validation = "true", version = "${dubbo.provider.OAuth2Service.version}")
private OAuth2Service oauth2Service;
@Reference(validation = "true", version = "${dubbo.provider.AdminService.version}")
private AdminService adminService;
@PostMapping("/login")
@ApiOperation(value = "手机号 + 密码登陆")
public CommonResult<AdminAuthenticationBO> login(AdminAuthenticationDTO adminAuthenticationDTO) {
// 增加计数
METRICS_LOGIN_TOTAL.increment();
// 执行登陆
return success(adminService.authentication(adminAuthenticationDTO));
}
// TODO 功能 logout
// TODO 功能 refresh_token
}