核心模型:RBAC权限模型
在档案管理系统中,权限分配的核心是采用RBAC模型。RBAC通过“用户-角色-权限”三层结构,将权限赋予角色,再将角色赋予用户,实现灵活、清晰的权限管理。
RBAC核心概念
RBAC模型包含四个关键元素:
用户 :系统的使用者,如档案管理员、部门领导、普通员工
角色 :权限的集合体,如“档案管理员”、“查阅员”、“审计员”
权限 :具体的操作许可,如“创建档案”、“修改档案”、“删除档案”、“查看档案”
会话 :用户激活角色的过程
数据库设计
创建以下数据库表结构,这是权限系统的数据基础。
用户表
```sql
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) UNIQUE NOT NULL,
password_hash VARCHAR(255) NOT NULL,
full_name VARCHAR(100),
department_id INT,
is_active BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
```
角色表
```sql
CREATE TABLE roles (
id INT PRIMARY KEY AUTO_INCREMENT,
role_code VARCHAR(50) UNIQUE NOT NULL,
role_name VARCHAR(100) NOT NULL,
description TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
```
权限表
```sql
CREATE TABLE permissions (
id INT PRIMARY KEY AUTO_INCREMENT,
perm_code VARCHAR(100) UNIQUE NOT NULL,
perm_name VARCHAR(200) NOT NULL,
module VARCHAR(50) COMMENT '所属模块,如档案管理、系统设置',
description TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
```
关联表
```sql
-- 用户-角色关联表
CREATE TABLE user_roles (
user_id INT NOT NULL,
role_id INT NOT NULL,
assigned_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (user_id, role_id),
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY (role_id) REFERENCES roles(id) ON DELETE CASCADE
);
-- 角色-权限关联表
CREATE TABLE role_permissions (
role_id INT NOT NULL,
perm_id INT NOT NULL,
assigned_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (role_id, perm_id),
FOREIGN KEY (role_id) REFERENCES roles(id) ON DELETE CASCADE,
FOREIGN KEY (perm_id) REFERENCES permissions(id) ON DELETE CASCADE
);
```
初始化数据
在系统部署时,需要先插入基础的角色和权限数据。
插入基础角色
```sql
INSERT INTO roles (role_code, role_name, description) VALUES
('SYS_ADMIN', '系统管理员', '拥有系统所有权限'),
('ARCHIVE_ADMIN', '档案管理员', '管理档案的创建、修改、归档'),
('ARCHIVE_VIEWER', '档案查阅员', '查看档案内容,无修改权限'),
('ARCHIVE_AUDITOR', '档案审计员', '查看档案操作日志和审计信息');
```
插入权限数据
```sql
-- 档案管理模块权限
INSERT INTO permissions (perm_code, perm_name, module) VALUES
('ARCHIVE_CREATE', '创建档案', 'archive'),
('ARCHIVE_EDIT', '编辑档案', 'archive'),
('ARCHIVE_DELETE', '删除档案', 'archive'),
('ARCHIVE_VIEW', '查看档案', 'archive'),
('ARCHIVE_DOWNLOAD', '下载档案', 'archive'),
('ARCHIVE_EXPORT', '导出档案列表', 'archive'),
('ARCHIVE_APPROVE', '审批档案', 'archive');
-- 系统管理模块权限
INSERT INTO permissions (perm_code, perm_name, module) VALUES
('USER_MANAGE', '用户管理', 'system'),
('ROLE_MANAGE', '角色管理', 'system'),
('PERM_MANAGE', '权限管理', 'system'),
('LOG_VIEW', '查看系统日志', 'system');
```
分配角色权限
```sql
-- 为档案管理员分配权限
INSERT INTO role_permissions (role_id, perm_id)
SELECT r.id, p.id FROM roles r, permissions p
WHERE r.role_code = 'ARCHIVE_ADMIN'
AND p.perm_code IN ('ARCHIVE_CREATE', 'ARCHIVE_EDIT', 'ARCHIVE_VIEW', 'ARCHIVE_DOWNLOAD', 'ARCHIVE_EXPORT');
-- 为档案查阅员分配权限
INSERT INTO role_permissions (role_id, perm_id)
SELECT r.id, p.id FROM roles r, permissions p
WHERE r.role_code = 'ARCHIVE_VIEWER'
AND p.perm_code IN ('ARCHIVE_VIEW', 'ARCHIVE_DOWNLOAD');
```
权限验证实现
在业务代码中实现权限验证逻辑,确保只有拥有相应权限的用户才能执行操作。
创建权限验证工具类
```java
public class PermissionChecker {
private static final String PERM_CACHE_PREFIX = "user_perms:";
/
检查用户是否拥有指定权限
@param userId 用户ID
@param permCode 权限代码
@return 是否拥有权限
/
public static boolean hasPermission(Integer userId, String permCode) {
if (userId == null || permCode == null) {
return false;
}
// 从缓存获取用户权限列表
Set
userPerms = getUserPermissionsFromCache(userId);
if (userPerms == null) {
// 缓存未命中,从数据库加载
userPerms = loadUserPermissionsFromDB(userId);
cacheUserPermissions(userId, userPerms);
}
return userPerms.contains(permCode);
}
/
从数据库加载用户所有权限
/
private static Set loadUserPermissionsFromDB(Integer userId) {
Set permissions = new HashSet<>();
String sql = "SELECT DISTINCT p.perm_code " +
"FROM users u " +
"JOIN user_roles ur ON u.id = ur.user_id " +
"JOIN role_permissions rp ON ur.role_id = rp.role_id " +
"JOIN permissions p ON rp.perm_id = p.id " +
"WHERE u.id = ? AND u.is_active = TRUE";
try (Connection conn = DataSource.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setInt(1, userId);
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
permissions.add(rs.getString("perm_code"));
}
} catch (SQLException e) {
throw new RuntimeException("加载用户权限失败", e);
}
return permissions;
}
}
```
实现权限拦截器
```java
@Aspect
@Component
public class PermissionInterceptor {
@Autowired
private HttpSession session;
/
权限检查切面
/
@Around("@annotation(RequirePermission)")
public Object checkPermission(ProceedingJoinPoint joinPoint) throws Throwable {
// 获取当前用户ID
Integer userId = (Integer) session.getAttribute("currentUserId");
if (userId == null) {
throw new UnauthorizedException("用户未登录");
}
// 获取注解中的权限代码
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
RequirePermission annotation = method.getAnnotation(RequirePermission.class);
String permCode = annotation.value();
// 检查权限
if (!PermissionChecker.hasPermission(userId, permCode)) {
throw new ForbiddenException("没有操作权限");
}
// 执行原方法
return joinPoint.proceed();
}
}
/
权限注解
/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RequirePermission {
String value();
}
```
前端权限控制
在前端界面中,根据用户权限动态控制界面元素的显示。
Vue.js权限指令实现
```javascript
// 权限指令
Vue.directive('permission', {
inserted: function (el, binding) {
const requiredPerm = binding.value;
const userPerms = Vue.prototype.$store.state.user.permissions;
if (!userPerms || !userPerms.includes(requiredPerm)) {
el.parentNode && el.parentNode.removeChild(el);
}
}
});
// 在组件中使用
创建档案
编辑档案
删除档案
```
React权限高阶组件
```jsx
// 权限高阶组件
const withPermission = (WrappedComponent, requiredPermission) => {
return class extends React.Component {
static contextType = AuthContext;
render() {
const { permissions } = this.context;
if (!permissions || !permissions.includes(requiredPermission)) {
return null;
}
return ;
}
};
};
// 使用示例
const ArchiveCreateButton = withPermission(
({ onClick }) => 创建档案 ,
'ARCHIVE_CREATE'
);
```
权限管理界面实现
提供管理员界面,用于管理用户角色和权限分配。
角色权限分配接口
```java
@RestController
@RequestMapping("/api/admin/roles")
public class RolePermissionController {
@Autowired
private RoleService roleService;
/
为角色分配权限
/
@PostMapping("/{roleId}/permissions")
@RequirePermission("PERM_MANAGE")
public ApiResponse assignPermissions(
@PathVariable Integer roleId,
@RequestBody List permissionIds) {
roleService.assignPermissionsToRole(roleId, permissionIds);
return ApiResponse.success("权限分配成功");
}
/
获取角色已有权限
/
@GetMapping("/{roleId}/permissions")
@RequirePermission("ROLE_MANAGE")
public ApiResponse> getRolePermissions(
@PathVariable Integer roleId) {
List permissions = roleService.getRolePermissions(roleId);
return ApiResponse.success(permissions);
}
}
```
用户角色分配接口
```java
@RestController
@RequestMapping("/api/admin/users")
public class UserRoleController {
@Autowired
private UserService userService;
/
为用户分配角色
/
@PostMapping("/{userId}/roles")
@RequirePermission("USER_MANAGE")
public ApiResponse assignRoles(
@PathVariable Integer userId,
@RequestBody List roleIds) {
userService.assignRolesToUser(userId, roleIds);
// 清除用户权限缓存
PermissionChecker.clearUserCache(userId);
return ApiResponse.success("角色分配成功");
}
}
```
权限数据缓存优化
使用Redis缓存用户权限数据,提高权限验证性能。
Redis缓存实现
```java
@Component
public class PermissionCacheService {
@Autowired
private RedisTemplate redisTemplate;
private static final long CACHE_EXPIRE_HOURS = 24;
/
缓存用户权限
/
public void cacheUserPermissions(Integer userId, Set permissions) {
String key = "user_perms:" + userId;
redisTemplate.opsForSet().add(key, permissions.toArray());
redisTemplate.expire(key, CACHE_EXPIRE_HOURS, TimeUnit.HOURS);
}
/
从缓存获取用户权限
/
public Set getUserPermissions(Integer userId) {
String key = "user_perms:" + userId;
Set members = redisTemplate.opsForSet().members(key);
if (members == null) {
return null;
}
return members.stream()
.map(Object::toString)
.collect(Collectors.toSet());
}
/
清除用户权限缓存
/
public void clearUserCache(Integer userId) {
String key = "user_perms:" + userId;
redisTemplate.delete(key);
}
}
```
权限变更通知机制
当用户权限发生变化时,及时通知相关系统组件。
权限变更事件发布
```java
@Component
public class PermissionChangeEventPublisher {
@Autowired
private ApplicationEventPublisher eventPublisher;
/
发布权限变更事件
/
public void publishPermissionChanged(Integer userId) {
PermissionChangedEvent event = new PermissionChangedEvent(this, userId);
eventPublisher.publishEvent(event);
}
}
/
权限变更事件
/
public class PermissionChangedEvent extends ApplicationEvent {
private final Integer userId;
public PermissionChangedEvent(Object source, Integer userId) {
super(source);
this.userId = userId;
}
public Integer getUserId() {
return userId;
}
}
```
WebSocket实时通知
```java
@Component
public class PermissionChangeListener {
@Autowired
private SimpMessagingTemplate messagingTemplate;
@EventListener
public void handlePermissionChanged(PermissionChangedEvent event) {
Integer userId = event.getUserId();
// 向该用户发送权限更新通知
messagingTemplate.convertAndSendToUser(
userId.toString(),
"/queue/permission-update",
new PermissionUpdateMessage("您的权限已更新,请重新登录或刷新页面")
);
}
}
```
权限审计日志
记录所有权限相关的操作,便于审计和追溯。
审计日志表设计
```sql
CREATE TABLE permission_audit_logs (
id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT NOT NULL,
action_type VARCHAR(50) NOT NULL COMMENT '操作类型:ASSIGN_ROLE, REMOVE_ROLE, ASSIGN_PERM, REMOVE_PERM',
target_type VARCHAR(50) NOT NULL COMMENT '目标类型:USER, ROLE',
target_id INT NOT NULL COMMENT '目标ID',
old_value TEXT COMMENT '变更前的值',
new_value TEXT COMMENT '变更后的值',
operator_id INT NOT NULL COMMENT '操作人ID',
ip_address VARCHAR(45),
user_agent TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_user_id (user_id),
INDEX idx_created_at (created_at)
);
```
审计日志记录
```java
@Aspect
@Component
public class PermissionAuditAspect {
@Autowired
private AuditLogService auditLogService;
@Autowired
private HttpServletRequest request;
@AfterReturning("@annotation(RequirePermission)")
public void logPermissionOperation(JoinPoint joinPoint) {
// 获取操作信息
String action = getActionName(joinPoint);
Object[] args = joinPoint.getArgs();
// 记录审计日志
AuditLog log = new AuditLog();
log.setActionType(action);
log.setIpAddress(getClientIp());
log.setUserAgent(request.getHeader("User-Agent"));
auditLogService.save(log);
}
}
```
按照以上步骤实现,你将建立一个完整的档案管理系统权限分配方案。这个方案具有清晰的层次结构、高效的验证机制、实时的变更通知和完整的审计追踪,能够满足各种规模的档案管理需求。