Java案例如何实现角色管理?

wen python案例 2

本文目录导读:

Java案例如何实现角色管理?

  1. 核心概念
  2. 数据库表设计
  3. 实体类设计(Java)
  4. 核心业务逻辑实现
  5. 权限校验(Spring Security整合)
  6. 前端实现示例(Vue3 + Element Plus)
  7. 面试追问与扩展

在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
前端 权限树组件、隐藏无权限按钮

这个案例涵盖了角色管理最核心的增删改查、权限分配以及访问控制,可以直接作为企业级后台系统的基线方案。

抱歉,评论功能暂时关闭!