本文目录导读:

在Java中实现角色管理通常涉及用户-角色-权限的经典RBAC(基于角色的访问控制)模型,以下是一个从数据库设计到代码实现的完整案例,包含基础CRUD和安全校验。
核心概念
- 用户(User) :系统使用者
- 角色(Role) :权限的集合(如:管理员、编辑、访客)
- 权限(Permission) :具体操作(如:用户管理-新增、文章管理-删除)
关系:用户 <—多对多—> 角色 <—多对多—> 权限
数据库表设计
-- 用户表
CREATE TABLE sys_user (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) UNIQUE NOT NULL,
password VARCHAR(255) NOT NULL,
status TINYINT DEFAULT 1 -- 1启用 0禁用
);
-- 角色表
CREATE TABLE sys_role (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
role_name VARCHAR(50) UNIQUE NOT NULL,
role_key VARCHAR(50) UNIQUE NOT NULL -- 角色标识(如admin)
);
-- 权限表
CREATE TABLE sys_permission (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
perm_name VARCHAR(50) NOT NULL,
perm_key VARCHAR(100) UNIQUE NOT NULL -- 权限标识(如user:add)
);
-- 用户-角色关联表
CREATE TABLE sys_user_role (
user_id BIGINT,
role_id BIGINT,
PRIMARY KEY (user_id, role_id)
);
-- 角色-权限关联表
CREATE TABLE sys_role_perm (
role_id BIGINT,
perm_id BIGINT,
PRIMARY KEY (role_id, perm_id)
);
实体类设计(Java)
// 用户实体
public class User {
private Long id;
private String username;
private String password;
private Integer status;
private List<Role> roles; // 用户拥有的角色列表
}
// 角色实体
public class Role {
private Long id;
private String roleName;
private String roleKey;
private List<Permission> permissions; // 角色拥有的权限列表
}
// 权限实体
public class Permission {
private Long id;
private String permName;
private String permKey;
}
核心业务逻辑实现
角色CRUD(以Service层为例)
@Service
public class RoleService {
@Autowired
private RoleMapper roleMapper;
@Autowired
private RolePermissionMapper rolePermissionMapper;
// 创建角色
@Transactional
public void createRole(Role role, List<Long> permissionIds) {
// 1. 新增角色
roleMapper.insert(role);
// 2. 绑定权限
if (permissionIds != null && !permissionIds.isEmpty()) {
rolePermissionMapper.batchInsert(role.getId(), permissionIds);
}
}
// 更新角色权限
@Transactional
public void updateRolePermissions(Long roleId, List<Long> newPermissionIds) {
// 先删除原有权限关联
rolePermissionMapper.deleteByRoleId(roleId);
// 再插入新的权限关联
rolePermissionMapper.batchInsert(roleId, newPermissionIds);
}
// 删除角色(连带删除关联表数据)
@Transactional
public void deleteRole(Long roleId) {
rolePermissionMapper.deleteByRoleId(roleId); // 删除角色-权限关联
userRoleMapper.deleteByRoleId(roleId); // 删除用户-角色关联
roleMapper.deleteById(roleId); // 删除角色本身
}
}
用户-角色分配
@Service
public class UserRoleService {
// 为用户分配角色
@Transactional
public void assignRolesToUser(Long userId, List<Long> roleIds) {
// 先清除用户原有角色
userRoleMapper.deleteByUserId(userId);
// 赋予新角色
userRoleMapper.batchInsert(userId, roleIds);
}
}
权限校验(Spring Security整合)
自定义权限注解
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface RequiresPermission {
String value(); // 如 "user:add"
}
权限切面实现
@Aspect
@Component
public class PermissionAspect {
@Around("@annotation(requiresPermission)")
public Object checkPermission(ProceedingJoinPoint joinPoint,
RequiresPermission requiresPermission) throws Throwable {
// 获取当前登录用户
User currentUser = SecurityContextHolder.getContext().getAuthentication();
// 获取用户所有权限
Set<String> userPermissions = currentUser.getAuthorities()
.stream()
.map(GrantedAuthority::getAuthority)
.collect(Collectors.toSet());
// 检查是否包含所需权限
if (!userPermissions.contains(requiresPermission.value())) {
throw new AccessDeniedException("无权限执行此操作");
}
return joinPoint.proceed();
}
}
使用示例(Controller层)
@RestController
@RequestMapping("/users")
public class UserController {
@RequiresPermission("user:add")
@PostMapping
public Result addUser(@RequestBody User user) {
userService.addUser(user);
return Result.success();
}
@RequiresPermission("user:delete")
@DeleteMapping("/{id}")
public Result deleteUser(@PathVariable Long id) {
userService.deleteUser(id);
return Result.success();
}
}
前端实现示例(Vue3 + Element Plus)
<template>
<div>
<!-- 角色列表 -->
<el-table :data="roles">
<el-table-column prop="roleName" label="角色名称" />
<el-table-column prop="roleKey" label="角色标识" />
<el-table-column label="操作">
<template #default="{ row }">
<el-button @click="editRole(row)">编辑权限</el-button>
<el-button @click="deleteRole(row.id)" type="danger">删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分配权限弹窗 -->
<el-dialog v-model="dialogVisible" title="分配权限">
<el-tree
ref="treeRef"
:data="allPermissions"
show-checkbox
node-key="id"
:default-checked-keys="checkedPermissions"
/>
<template #footer>
<el-button @click="savePermissions">保存</el-button>
</template>
</el-dialog>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import axios from 'axios'
const roles = ref([])
const dialogVisible = ref(false)
const allPermissions = ref([])
const checkedPermissions = ref([])
const currentRoleId = ref(null)
// 获取角色列表
const fetchRoles = async () => {
const res = await axios.get('/api/roles')
roles.value = res.data
}
// 编辑角色权限
const editRole = (role) => {
currentRoleId.value = role.id
// 获取该角色已拥有的权限ID
axios.get(`/api/roles/${role.id}/permissions`).then(res => {
checkedPermissions.value = res.data // [1, 3, 5]
})
dialogVisible.value = true
}
// 保存权限分配
const savePermissions = () => {
const selectedIds = treeRef.value.getCheckedKeys()
axios.put(`/api/roles/${currentRoleId.value}/permissions`, selectedIds)
.then(() => {
ElMessage.success('权限更新成功')
dialogVisible.value = false
})
}
onMounted(fetchRoles)
</script>
面试追问与扩展
Q1:如果角色和权限数据量很大(百万级),如何优化?
- 使用Redis缓存用户权限(如:
user:permissions:{userId}),减少数据库查询。 - 权限判断走位图(BitMap) ,适用于固定权限集。
- 采用数据脱敏+读写分离。
Q2:如何实现角色互斥(一个用户不能同时拥有“管理员”和“普通用户”)?
在前端限制选择,后端插入前校验:
// 检查用户是否已有互斥角色
List<Role> existingRoles = userRoleMapper.findRolesByUserId(userId);
if (existingRoles.stream().anyMatch(r -> r.getRoleKey().equals("admin"))
&& newRoles.contains("normal")) {
throw new BusinessException("用户已是管理员,不能分配普通用户角色");
}
Q3:RBAC的扩展模型?
- RBAC1:支持角色继承(如:超级管理员 -> 管理员 -> 编辑)
- RBAC2:增加约束(如:角色互斥、基数限制)
- ABAC(基于属性的访问控制) :结合用户属性、资源属性、环境条件动态判断。
| 层级 | 实现方式 |
|---|---|
| 数据层 | 5张标准RBAC表 |
| 业务层 | 角色CRUD、用户-角色分配、权限-角色绑定 |
| 安全校验 | 自定义注解 + AOP 或 Spring Security |
| 前端 | 权限树组件、隐藏无权限按钮 |
这个案例涵盖了角色管理最核心的增删改查、权限分配以及访问控制,可以直接作为企业级后台系统的基线方案。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播