feat(system): 重构角色权限模块

- 移除 Authority 相关代码,改为使用 Menu 进行权限管理
- 重构 Role 和 RoleMenu 实体,以及相关 repository 和 service
- 更新菜单相关 API,增加菜单权限校验- 优化角色创建和编辑逻辑,支持菜单权限分配
- 更新 RoleVo 类,使用 Menu 替代 Authority
This commit is contained in:
zhuangtianxiang 2025-01-10 16:51:12 +08:00
parent 6bb8e7cefa
commit cde42f955d
13 changed files with 102 additions and 125 deletions

View File

@ -37,6 +37,7 @@ public class FirstTimeInitializer implements CommandLineRunner {
private final DeptRepository deptRepo; private final DeptRepository deptRepo;
private final PasswordEncoder passwordEncoder; private final PasswordEncoder passwordEncoder;
//TODO 初始化赋权给admin
@Override @Override
public void run(String... args) { public void run(String... args) {
// if (authorityService.count() == 0L) { // if (authorityService.count() == 0L) {

View File

@ -26,7 +26,7 @@ public class MenuController {
/** /**
* 获取菜单树 * 获取菜单树
*/ */
@GetMapping("/menu") @GetMapping
public List<MenuVo> menu(@AuthenticationPrincipal UserDetailsImpl userDetails) { public List<MenuVo> menu(@AuthenticationPrincipal UserDetailsImpl userDetails) {
List<MenuVo> list = service.selectByUserId(userDetails.getId(), Menu.Type.PAGE).stream().map(MenuVo::new).toList(); List<MenuVo> list = service.selectByUserId(userDetails.getId(), Menu.Type.PAGE).stream().map(MenuVo::new).toList();
return TreeUtil.makeTree( return TreeUtil.makeTree(
@ -40,16 +40,16 @@ public class MenuController {
/** /**
* 新建菜单 * 新建菜单
*/ */
@PostMapping("") @PostMapping
public Menu create(MenuDto dto) { public Menu create(@RequestBody MenuDto dto) {
return service.create(dto); return service.create(dto);
} }
/** /**
* 更新菜单 * 更新菜单
*/ */
@PatchMapping("") @PatchMapping("/{id}")
public Menu update(MenuDto dto, Long id) { public Menu update(@RequestBody MenuDto dto, @PathVariable("id") Long id) {
return service.update(dto, id); return service.update(dto, id);
} }
@ -57,7 +57,7 @@ public class MenuController {
* 删除菜单 * 删除菜单
*/ */
@DeleteMapping("/{id}") @DeleteMapping("/{id}")
public Boolean delete(@PathVariable Long id) { public Boolean delete(@PathVariable("id") Long id) {
return service.delete(id); return service.delete(id);
} }
} }

View File

@ -4,7 +4,6 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zsc.edu.gateway.modules.system.dto.AuthorityCreateDto; import com.zsc.edu.gateway.modules.system.dto.AuthorityCreateDto;
//import com.zsc.edu.gateway.modules.system.dto.RoleAuthCreateDto; //import com.zsc.edu.gateway.modules.system.dto.RoleAuthCreateDto;
import com.zsc.edu.gateway.modules.system.dto.RoleDto; import com.zsc.edu.gateway.modules.system.dto.RoleDto;
import com.zsc.edu.gateway.modules.system.entity.Authority;
import com.zsc.edu.gateway.modules.system.entity.Role; import com.zsc.edu.gateway.modules.system.entity.Role;
import com.zsc.edu.gateway.modules.system.query.RoleQuery; import com.zsc.edu.gateway.modules.system.query.RoleQuery;
import com.zsc.edu.gateway.modules.system.service.RoleAuthService; import com.zsc.edu.gateway.modules.system.service.RoleAuthService;
@ -28,7 +27,6 @@ public class RoleController {
private final RoleService service; private final RoleService service;
private final RoleAuthService roleAuthService;
/** /**
* 返回所有角色列表 hasAuthority('SYSTEM:ROLE:QUERY') * 返回所有角色列表 hasAuthority('SYSTEM:ROLE:QUERY')
@ -49,9 +47,8 @@ public class RoleController {
*/ */
@PostMapping @PostMapping
@PreAuthorize("hasAuthority('system:role:create')") @PreAuthorize("hasAuthority('system:role:create')")
public Boolean create(@RequestBody RoleDto dto) { public Role create(@RequestBody RoleDto dto) {
Role role= service.create(dto); return service.create(dto);
return role != null;
} }
/** /**
@ -63,9 +60,7 @@ public class RoleController {
*/ */
@PatchMapping("{id}") @PatchMapping("{id}")
@PreAuthorize("hasAuthority('system:role:update')") @PreAuthorize("hasAuthority('system:role:update')")
public Boolean update(@RequestBody RoleDto dto, @PathVariable("id") Long id) { public Role update(@RequestBody RoleDto dto, @PathVariable("id") Long id) {
// Role role = roleMapper.toEntity(dto);
// role.setId(id);
return service.edit(dto, id); return service.edit(dto, id);
} }
@ -105,15 +100,5 @@ public class RoleController {
return service.delete(id); return service.delete(id);
} }
/**
* 为角色添加权限 hasAuthority('SYSTEM:ROLE:AUTHED')
*
* @return RoleAuthority 新的角色权限
*/
@PostMapping("/saveAuth/{id}")
@PreAuthorize("hasAuthority('system:role:create')")
public Boolean addAuthed(@PathVariable Long id, @RequestBody Set<AuthorityCreateDto> authorities) {
return service.saveRoleAuths(id,authorities);
}
} }

View File

@ -1,6 +1,7 @@
package com.zsc.edu.gateway.modules.system.dto; package com.zsc.edu.gateway.modules.system.dto;
import com.zsc.edu.gateway.modules.system.entity.Menu; import com.zsc.edu.gateway.modules.system.entity.Menu;
import jakarta.validation.constraints.NotBlank;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
@ -13,7 +14,7 @@ import lombok.NoArgsConstructor;
@NoArgsConstructor @NoArgsConstructor
public class MenuDto { public class MenuDto {
/** /**
* 子部门ID * 父菜单ID
*/ */
private Long pid; private Long pid;
/** /**
@ -23,6 +24,7 @@ public class MenuDto {
/** /**
* 名称 * 名称
*/ */
@NotBlank(message = "名字不能为空")
private String name; private String name;
/** /**
* 路径 * 路径
@ -52,8 +54,4 @@ public class MenuDto {
* 权限 * 权限
*/ */
private String permissions; private String permissions;
/**
* 权限标识
*/
private String authority = "";
} }

View File

@ -35,7 +35,7 @@ public class RoleDto {
/** /**
* 权限列表 * 权限列表
*/ */
public Set<AuthorityCreateDto> authorities; public Set<Long> menuIds;
} }

View File

@ -27,6 +27,4 @@ public class RoleMenu implements Serializable {
*/ */
private Long menuId; private Long menuId;
// @TableField(exist = false)
// private Set<Authority> authorities;
} }

View File

@ -16,7 +16,6 @@ public interface MenuRepository extends BaseMapper<Menu> {
List<Menu> selectByRoleId(Long roleId); List<Menu> selectByRoleId(Long roleId);
List<Menu> selectByUserId(Long userId, Menu.Type type); List<Menu> selectByUserId(Long userId, Menu.Type type);
} }

View File

@ -7,5 +7,4 @@ import com.zsc.edu.gateway.modules.system.entity.RoleMenu;
* @author Yao * @author Yao
*/ */
public interface RoleMenuRepository extends BaseMapper<RoleMenu> { public interface RoleMenuRepository extends BaseMapper<RoleMenu> {
} }

View File

@ -1,14 +1,10 @@
package com.zsc.edu.gateway.modules.system.service; package com.zsc.edu.gateway.modules.system.service;
import com.zsc.edu.gateway.modules.system.dto.AuthorityCreateDto;
import com.zsc.edu.gateway.modules.system.dto.RoleDto; import com.zsc.edu.gateway.modules.system.dto.RoleDto;
import com.zsc.edu.gateway.modules.system.entity.Authority;
import com.zsc.edu.gateway.modules.system.entity.Role; import com.zsc.edu.gateway.modules.system.entity.Role;
import com.baomidou.mybatisplus.extension.service.IService; import com.baomidou.mybatisplus.extension.service.IService;
import com.zsc.edu.gateway.modules.system.vo.RoleVo; import com.zsc.edu.gateway.modules.system.vo.RoleVo;
import java.util.Set;
/** /**
* <p> * <p>
* 角色表 服务类 * 角色表 服务类
@ -21,7 +17,7 @@ public interface RoleService extends IService<Role> {
Role create(RoleDto roleDto); Role create(RoleDto roleDto);
Boolean edit(RoleDto roleDto, Long id); Role edit(RoleDto roleDto, Long id);
RoleVo detail(Long id); RoleVo detail(Long id);
@ -29,5 +25,4 @@ public interface RoleService extends IService<Role> {
Boolean delete(Long id); Boolean delete(Long id);
Boolean saveRoleAuths(Long roleId, Set<AuthorityCreateDto> authorities);
} }

View File

@ -35,6 +35,12 @@ public class MenuServiceImpl extends ServiceImpl<MenuRepository, Menu> implement
@Override @Override
public Menu create(MenuDto dto) { public Menu create(MenuDto dto) {
if (baseMapper.selectList(new LambdaQueryWrapper<Menu>().eq(Menu::getName, dto.getName())) != null) {
throw new ConstraintException("该菜单名已存在!请检查输入表单是否出错!");
}
if (baseMapper.selectList(new LambdaQueryWrapper<Menu>().eq(Menu::getPermissions, dto.getPermissions())) != null) {
throw new ConstraintException("该权限已存在!请检查输入表单是否出错!");
}
Menu menu = mapper.toEntity(dto); Menu menu = mapper.toEntity(dto);
baseMapper.insert(menu); baseMapper.insert(menu);
return menu; return menu;

View File

@ -1,17 +1,12 @@
package com.zsc.edu.gateway.modules.system.service.impl; package com.zsc.edu.gateway.modules.system.service.impl;
import com.zsc.edu.gateway.exception.ConstraintException; import com.zsc.edu.gateway.exception.ConstraintException;
import com.zsc.edu.gateway.modules.system.dto.AuthorityCreateDto;
import com.zsc.edu.gateway.modules.system.dto.RoleDto; import com.zsc.edu.gateway.modules.system.dto.RoleDto;
import com.zsc.edu.gateway.modules.system.entity.Authority; import com.zsc.edu.gateway.modules.system.entity.*;
import com.zsc.edu.gateway.modules.system.entity.Role;
import com.zsc.edu.gateway.modules.system.entity.RoleAuthority;
import com.zsc.edu.gateway.modules.system.entity.UserRole;
import com.zsc.edu.gateway.modules.system.mapper.RoleMapper; import com.zsc.edu.gateway.modules.system.mapper.RoleMapper;
import com.zsc.edu.gateway.modules.system.repo.AuthorityRepository; import com.zsc.edu.gateway.modules.system.repo.RoleMenuRepository;
import com.zsc.edu.gateway.modules.system.repo.RoleRepository; import com.zsc.edu.gateway.modules.system.repo.RoleRepository;
import com.zsc.edu.gateway.modules.system.repo.UserRolesRepository; import com.zsc.edu.gateway.modules.system.repo.UserRolesRepository;
import com.zsc.edu.gateway.modules.system.service.RoleAuthService;
import com.zsc.edu.gateway.modules.system.service.RoleService; import com.zsc.edu.gateway.modules.system.service.RoleService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
@ -19,10 +14,7 @@ import com.zsc.edu.gateway.modules.system.vo.RoleVo;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.HashSet;
import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
@ -40,8 +32,7 @@ public class RoleServiceImpl extends ServiceImpl<RoleRepository, Role> implement
private final RoleMapper mapper; private final RoleMapper mapper;
private final UserRolesRepository urRepo; private final UserRolesRepository urRepo;
private final RoleAuthService roleAuthService; private final RoleMenuRepository roleMenuRepository;
private final AuthorityRepository authorityRepository;
private final RoleRepository roleRepository; private final RoleRepository roleRepository;
@Override @Override
@ -50,9 +41,15 @@ public class RoleServiceImpl extends ServiceImpl<RoleRepository, Role> implement
if (existsByName) { if (existsByName) {
throw new ConstraintException("name", dto.name, "角色已存在"); throw new ConstraintException("name", dto.name, "角色已存在");
} }
Role role = mapper.toEntity(dto); Role role = new Role();
role.setName(dto.getName());
role.setRemark(dto.getRemark());
save(role); save(role);
// saveRoleAuths(role.getId(), role.getAuthorities()); if (dto.getMenuIds() != null) {
roleMenuRepository.insert(
dto.getMenuIds().stream()
.map(menuId -> new RoleMenu(role.getId(), menuId)).collect(Collectors.toList()));
}
return role; return role;
} }
@ -69,46 +66,37 @@ public class RoleServiceImpl extends ServiceImpl<RoleRepository, Role> implement
if (hasUser) { if (hasUser) {
throw new ConstraintException("存在与本角色绑定的用户,请先删除用户"); throw new ConstraintException("存在与本角色绑定的用户,请先删除用户");
} }
roleMenuRepository.delete(new LambdaQueryWrapper<RoleMenu>().eq(RoleMenu::getRoleId, id));
// 删除角色权限关联关系
roleAuthService.removeByRoleId(id);
return removeById(id); return removeById(id);
} }
@Override @Override
public Boolean edit(RoleDto dto, Long id) { public Role edit(RoleDto dto, Long id) {
Role existingRole = getById(id); Role selectyRole = getById(id);
if (existingRole == null) { if (selectyRole == null) {
throw new ConstraintException("id", id.toString(), "角色不存在"); throw new ConstraintException("id", id.toString(), "角色不存在");
} }
if (!Objects.equals(existingRole.getName(), dto.getName()) && if (!Objects.equals(selectyRole.getName(), dto.getName()) &&
count(new LambdaQueryWrapper<Role>().eq(Role::getName, dto.getName())) > 0) { count(new LambdaQueryWrapper<Role>().eq(Role::getName, dto.getName())) > 0) {
throw new ConstraintException("name", dto.getName(), "同名角色已存在"); throw new ConstraintException("name", dto.getName(), "同名角色已存在");
} }
mapper.convert(dto, existingRole); Role role = new Role();
if (existingRole.getAuthorities() != null) { role.setName(dto.getName());
roleAuthService.remove(new LambdaQueryWrapper<RoleAuthority>().eq(RoleAuthority::getRoleId, id)); role.setRemark(dto.getRemark());
saveRoleAuths(id, dto.getAuthorities()); updateById(role);
if (dto.getMenuIds() != null) {
roleMenuRepository.delete(new LambdaQueryWrapper<RoleMenu>().eq(RoleMenu::getRoleId, id));
roleMenuRepository.insert(
dto.getMenuIds().stream()
.map(menuId -> new RoleMenu(id, menuId)).collect(Collectors.toList()));
} }
return updateById(existingRole); return role;
} }
@Override @Override
public RoleVo detail(Long id) { public RoleVo detail(Long id) {
// Role role = getById(id);
// // List<RoleAuthority> roleAuthorities = roleAuthService.list(new LambdaQueryWrapper<RoleAuthority>().eq(RoleAuthority::getRoleId, role.id));
// role.authorities = authorityRepository.selectAuthoritiesByRoleId(role.id);
return roleRepository.selectRoleById(id); return roleRepository.selectRoleById(id);
} }
@Override
public Boolean saveRoleAuths(Long roleId, Set<AuthorityCreateDto> authorities) {
// 保存角色关联权限
List<RoleAuthority> roleAuthorities = authorities.stream()
.map(authority ->
new RoleAuthority(roleId, authorityRepository.getAuthorityIdByName(authority.getName())))
.collect(Collectors.toList());
return roleAuthService.saveBatch(roleAuthorities);
}
} }

View File

@ -1,60 +1,65 @@
package com.zsc.edu.gateway.modules.system.vo; package com.zsc.edu.gateway.modules.system.vo;
import com.zsc.edu.gateway.modules.system.entity.Authority; import com.zsc.edu.gateway.modules.system.entity.Menu;
import lombok.Data; import lombok.Data;
import java.util.Date; import java.time.LocalDateTime;
import java.util.List; import java.util.Set;
/** /**
* @author lenovo * @author zhuang
*/ */
@Data @Data
public class RoleVo { public class RoleVo {
/** /**
* 自增主键 * 自增主键
*/ */
public Long id; public Long id;
/** /**
* 角色 * 唯一
*/ */
private String name; public String name;
/**
*级别
*/
private Integer level;
/**
* 描述
*/
private String description;
/**
* 数据权限
*/
private String dataScope;
/**
* 创建人
*/
private String createBy;
/**
* 更新人
*/
private String updateBy;
/**
* 创建时间
*/
private Date createTime;
/**
* 更新时间
*/
private Date updateTime;
/** /**
* 启用状态 * 启用状态
*/ */
private Boolean enabled; private Boolean enabled = true;
/**
* 备注
*/
private String remark;
private List<Authority> authorities; /**
* 部门ID(权限)
*/
public Long deptId;
/**
* 备注说明
*/
public String roleRemark;
/**
* 创建时间
*/
public LocalDateTime createTime;
/*
* 创建人
*
*/
public String createBy;
/**
* 更新时间
*/
public LocalDateTime updateTime;
/*
* 更新人
*
* */
public String updateBy;
/**
* 权限集合
*/
public Set<Menu> menus;
} }

View File

@ -9,20 +9,23 @@
<result column="create_time" jdbcType="DATE" property="createTime"/> <result column="create_time" jdbcType="DATE" property="createTime"/>
<result column="update_time" jdbcType="DATE" property="updateTime"/> <result column="update_time" jdbcType="DATE" property="updateTime"/>
<result column="enabled" jdbcType="BIT" property="enabled"/> <result column="enabled" jdbcType="BIT" property="enabled"/>
<result column="remark" jdbcType="VARCHAR" property="remark"/> <result column="remark" jdbcType="VARCHAR" property="roleRemark"/>
<collection property="authorities" ofType="com.zsc.edu.gateway.modules.system.entity.Authority" autoMapping="true" columnPrefix="authority_"> <collection property="menus" ofType="com.zsc.edu.gateway.modules.system.entity.Menu" autoMapping="true"
columnPrefix="menu_">
<id column="id" jdbcType="BIT" property="id"/> <id column="id" jdbcType="BIT" property="id"/>
<result column="name" jdbcType="VARCHAR" property="name"/> <result column="permissions" jdbcType="VARCHAR" property="permissions"/>
<result column="remark" jdbcType="VARCHAR" property="remark"/> <result column="remark" jdbcType="VARCHAR" property="remark"/>
</collection> </collection>
</resultMap> </resultMap>
<select id="selectRoleById" resultMap="roleMap"> <select id="selectRoleById" resultMap="roleMap">
select sr.*, select sr.*,
sa.id as authority_id, sa.name as authority_name, sa.enabled as authority_enabled,sa.remark as authority_remark,sa.create_by as authority_create_by,sa.create_time as authority_create_time,sa.update_by as authority_update_by,sa.update_time as authority_update_time sm.id AS menu_id,
sm.permissions AS menu_permissions,
sm.remark AS menu_remark
from sys_role sr from sys_role sr
left join sys_role_authorities sra on sr.id=sra.role_id left join sys_role_menu srm on sr.id = srm.role_id
left join sys_authority sa on sra.authority_id=sa.id left join sys_menu sm on srm.menu_id = sm.id
where sr.id=#{roleId} where sr.id=#{roleId}
</select> </select>