网站首页/ 信息中心/ 档案百科/

档案管理系统权限管理实战:RBAC模型与Spring Security实现指南

发布时间:2026年08月25日 01:25:04 浏览量:0

一、权限管理核心模型选择

档案管理系统的权限控制必须基于RBAC(基于角色的访问控制)模型。该模型将用户与权限解耦,通过角色作为中间层,大幅降低权限维护复杂度。

1.1 四层权限模型设计

标准的RBAC模型包含以下四个核心实体:

1.2 权限粒度设计原则

权限设计必须遵循最小权限原则,具体操作权限分为三个层级:

二、数据库表结构设计

创建以下6张核心表,MySQL建表语句如下:

```sql -- 用户表 CREATE TABLE sys_user ( id BIGINT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) UNIQUE NOT NULL COMMENT '登录账号', password VARCHAR(100) NOT NULL COMMENT '加密后的密码', real_name VARCHAR(50) NOT NULL COMMENT '真实姓名', department_id BIGINT NOT NULL COMMENT '所属部门ID', is_enabled TINYINT DEFAULT 1 COMMENT '是否启用:0-禁用,1-启用', created_time DATETIME DEFAULT CURRENT_TIMESTAMP ) COMMENT='系统用户表'; -- 角色表 CREATE TABLE sys_role ( id BIGINT PRIMARY KEY AUTO_INCREMENT, role_code VARCHAR(50) UNIQUE NOT NULL COMMENT '角色编码', role_name VARCHAR(50) NOT NULL COMMENT '角色名称', description VARCHAR(200) COMMENT '角色描述' ) COMMENT='系统角色表'; -- 权限表 CREATE TABLE sys_permission ( id BIGINT PRIMARY KEY AUTO_INCREMENT, perm_code VARCHAR(100) UNIQUE NOT NULL COMMENT '权限标识', perm_name VARCHAR(50) NOT NULL COMMENT '权限名称', resource_type VARCHAR(20) NOT NULL COMMENT '资源类型:MENU-菜单,BUTTON-按钮,API-接口', resource_path VARCHAR(200) COMMENT '资源路径', parent_id BIGINT DEFAULT 0 COMMENT '父权限ID', sort_order INT DEFAULT 0 COMMENT '排序号' ) COMMENT='系统权限表'; -- 用户角色关联表 CREATE TABLE sys_user_role ( id BIGINT PRIMARY KEY AUTO_INCREMENT, user_id BIGINT NOT NULL, role_id BIGINT NOT NULL, UNIQUE KEY uk_user_role (user_id, role_id) ) COMMENT='用户角色关联表'; -- 角色权限关联表 CREATE TABLE sys_role_permission ( id BIGINT PRIMARY KEY AUTO_INCREMENT, role_id BIGINT NOT NULL, perm_id BIGINT NOT NULL, UNIQUE KEY uk_role_perm (role_id, perm_id) ) COMMENT='角色权限关联表'; -- 部门表(用于数据权限控制) CREATE TABLE sys_department ( id BIGINT PRIMARY KEY AUTO_INCREMENT, dept_code VARCHAR(50) UNIQUE NOT NULL COMMENT '部门编码', dept_name VARCHAR(100) NOT NULL COMMENT '部门名称', parent_id BIGINT DEFAULT 0 COMMENT '父部门ID', full_path VARCHAR(500) COMMENT '部门全路径' ) COMMENT='部门表'; ```

三、Spring Security集成配置

在Spring Boot项目中集成Spring Security 6.x,实现完整的认证授权流程。

3.1 Maven依赖配置

在pom.xml中添加以下依赖:

```xml org.springframework.boot spring-boot-starter-security org.springframework.boot spring-boot-starter-web com.auth0 java-jwt 4.4.0 org.mybatis.spring.boot mybatis-spring-boot-starter 3.0.3 ```

3.2 Security配置类

创建SecurityConfig.java配置文件:

```java @Configuration @EnableWebSecurity @RequiredArgsConstructor public class SecurityConfig { private final JwtAuthenticationFilter jwtAuthFilter; private final UserDetailsServiceImpl userDetailsService; @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .csrf(AbstractHttpConfigurer::disable) .sessionManagement(session -> session .sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .authorizeHttpRequests(auth -> auth .requestMatchers("/api/auth/login").permitAll() .requestMatchers("/api/auth/register").permitAll() .requestMatchers("/api/admin/").hasRole("ADMIN") .requestMatchers("/api/archive/create").hasAuthority("archive:create") .requestMatchers("/api/archive/delete").hasAuthority("archive:delete") .anyRequest().authenticated()) .addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class); return http.build(); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Bean public AuthenticationManager authenticationManager( AuthenticationConfiguration config) throws Exception { return config.getAuthenticationManager(); } } ```

3.3 自定义UserDetailsService

实现用户详情查询服务,从数据库加载用户权限:

```java @Service @RequiredArgsConstructor public class UserDetailsServiceImpl implements UserDetailsService { private final UserMapper userMapper; private final RoleMapper roleMapper; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { // 查询用户基本信息 SysUser user = userMapper.selectByUsername(username); if (user == null) { throw new UsernameNotFoundException("用户不存在"); } // 查询用户角色和权限 List roles = roleMapper.selectRoleCodesByUserId(user.getId()); List permissions = roleMapper.selectPermissionsByUserId(user.getId()); // 构建权限集合 List authorities = new ArrayList<>(); roles.forEach(role -> authorities.add(new SimpleGrantedAuthority("ROLE_" + role))); permissions.forEach(perm -> authorities.add(new SimpleGrantedAuthority(perm))); return new org.springframework.security.core.userdetails.User( user.getUsername(), user.getPassword(), user.getIsEnabled() == 1, true, true, true, authorities ); } } ```

四、JWT令牌实现

使用JWT实现无状态认证,避免Session存储。

4.1 JWT工具类

创建JwtUtil.java处理令牌生成与验证:

```java @Component public class JwtUtil { @Value("${jwt.secret}") private String secret; @Value("${jwt.expiration}") private Long expiration; // 生成令牌 public String generateToken(String username, List authorities) { Date now = new Date(); Date expiryDate = new Date(now.getTime() + expiration); return JWT.create() .withSubject(username) .withIssuedAt(now) .withExpiresAt(expiryDate) .withClaim("authorities", authorities) .sign(Algorithm.HMAC256(secret)); } // 验证令牌 public boolean validateToken(String token) { try { JWT.require(Algorithm.HMAC256(secret)).build().verify(token); return true; } catch (Exception e) { return false; } } // 从令牌获取用户名 public String getUsernameFromToken(String token) { return JWT.require(Algorithm.HMAC256(secret)) .build() .verify(token) .getSubject(); } // 从令牌获取权限列表 public List getAuthoritiesFromToken(String token) { return JWT.require(Algorithm.HMAC256(secret)) .build() .verify(token) .getClaim("authorities") .asList(String.class); } } ```

4.2 JWT认证过滤器

创建过滤器拦截请求并验证JWT:

```java @Component @RequiredArgsConstructor public class JwtAuthenticationFilter extends OncePerRequestFilter { private final JwtUtil jwtUtil; private final UserDetailsServiceImpl userDetailsService; @Override protected void doFilterInternal( HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String authHeader = request.getHeader("Authorization"); if (authHeader != null && authHeader.startsWith("Bearer ")) { String token = authHeader.substring(7); if (jwtUtil.validateToken(token)) { String username = jwtUtil.getUsernameFromToken(token); UserDetails userDetails = userDetailsService.loadUserByUsername(username); UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken( userDetails, null, userDetails.getAuthorities()); authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); SecurityContextHolder.getContext().setAuthentication(authentication); } } filterChain.doFilter(request, response); } } ```

五、数据权限控制实现

档案管理系统权限管理实战:RBAC模型与Spring Security实现指南

通过MyBatis拦截器实现部门级数据隔离。

5.1 数据权限上下文

创建ThreadLocal存储当前用户的数据权限范围:

```java public class DataPermissionContext { private static final ThreadLocal> DEPT_IDS = new ThreadLocal<>(); public static void setDeptIds(Set deptIds) { DEPT_IDS.set(deptIds); } public static Set getDeptIds() { return DEPT_IDS.get(); } public static void clear() { DEPT_IDS.remove(); } } ```

5.2 MyBatis拦截器

创建拦截器自动添加数据权限SQL:

```java @Intercepts({ @Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class}) }) @Component public class DataPermissionInterceptor implements Interceptor { @Override public Object intercept(Invocation invocation) throws Throwable { StatementHandler handler = (StatementHandler) invocation.getTarget(); MetaObject metaObject = SystemMetaObject.forObject(handler); // 获取原始SQL MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement"); String sql = (String) metaObject.getValue("delegate.boundSql.sql"); // 检查是否需要数据权限过滤 if (needDataPermission(mappedStatement)) { Set deptIds = DataPermissionContext.getDeptIds(); if (deptIds != null && !deptIds.isEmpty()) { String newSql = addDataPermissionCondition(sql, deptIds); metaObject.setValue("delegate.boundSql.sql", newSql); } } return invocation.proceed(); } private boolean needDataPermission(MappedStatement ms) { // 根据Mapper方法名判断是否需要数据权限 String methodName = ms.getId(); return methodName.contains("select") || methodName.contains("query"); } private String addDataPermissionCondition(String sql, Set deptIds) { String condition = "department_id IN (" + deptIds.stream().map(String::valueOf).collect(Collectors.joining(",")) + ")"; if (sql.toUpperCase().contains("WHERE")) { return sql + " AND " + condition; } else { return sql + " WHERE " + condition; } } } ```

六、前端权限控制实现

Vue.js前端权限控制方案。

6.1 权限指令实现

创建自定义指令控制按钮显示:

```javascript // permission.js const permission = { mounted(el, binding) { const { value } = binding const permissions = store.getters.permissions if (value && value instanceof Array && value.length > 0) { const requiredPermissions = value const hasPermission = permissions.some(perm => { return requiredPermissions.includes(perm) }) if (!hasPermission) { el.parentNode && el.parentNode.removeChild(el) } } else { throw new Error(`需要权限标识,如 v-permission="['archive:create']"`) } } } // main.js中注册指令 app.directive('permission', permission) ```

6.2 动态路由配置

根据用户权限动态生成路由:

```javascript // 路由守卫中处理动态路由 router.beforeEach(async (to, from, next) => { if (store.getters.token) { if (store.getters.permissions.length === 0) { try { // 获取用户权限 const { permissions } = await store.dispatch('user/getUserInfo') // 生成可访问路由 const accessRoutes = await store.dispatch('permission/generateRoutes', permissions) // 动态添加路由 accessRoutes.forEach(route => { router.addRoute(route) }) next({ ...to, replace: true }) } catch (error) { next('/login') } } else { next() } } else { next() } }) ```

七、权限变更实时生效方案

解决权限修改后需要重新登录的问题。

7.1 Redis缓存权限数据

使用Redis缓存用户权限,支持实时更新:

```java @Service public class PermissionCacheService { @Autowired private RedisTemplate redisTemplate; private static final String PERMISSION_KEY_PREFIX = "user:perms:"; // 缓存用户权限 public void cacheUserPermissions(Long userId, List permissions) { String key = PERMISSION_KEY_PREFIX + userId; redisTemplate.opsForValue().set(key, permissions, 2, TimeUnit.HOURS); } // 获取缓存权限 public List getCachedPermissions(Long userId) { String key = PERMISSION_KEY_PREFIX + userId; Object cached = redisTemplate.opsForValue().get(key); return cached != null ? (List) cached : null; } // 清除权限缓存 public void clearUserPermissions(Long userId) { String key = PERMISSION_KEY_PREFIX + userId; redisTemplate.delete(key); } } ```

7.2 权限变更通知机制

当管理员修改用户权限时,发送WebSocket通知:

```java @RestController @RequestMapping("/api/admin/permission") public class PermissionAdminController { @Autowired private WebSocketServer webSocketServer; @PostMapping("/update") public Result updateUserPermissions(@RequestBody PermissionUpdateDTO dto) { // 1. 更新数据库权限 permissionService.updateUserPermissions(dto.getUserId(), dto.getPermissions()); // 2. 清除Redis缓存 permissionCacheService.clearUserPermissions(dto.getUserId()); // 3. 通知前端刷新权限 webSocketServer.sendMessage( dto.getUserId(), "PERMISSION_UPDATED" ); return Result.success(); } } ```

八、完整部署与测试流程

8.1 初始化数据脚本

执行以下SQL初始化基础权限数据:

```sql -- 插入基础角色 INSERT INTO sys_role (role_code, role_name, description) VALUES ('admin', '系统管理员', '拥有所有权限'), ('archive_manager', '档案管理员', '档案管理相关权限'), ('archive_viewer', '档案查阅员', '档案查阅权限'); -- 插入基础权限 INSERT INTO sys_permission (perm_code, perm_name, resource_type, resource_path, parent_id) VALUES ('archive:create', '创建档案', 'BUTTON', '/archive/create', 0), ('archive:delete', '删除档案', 'BUTTON', '/archive/delete', 0), ('archive:view', '查看档案', 'API', '/api/archive/', 0), ('archive:export', '导出档案', 'BUTTON', '/archive/export', 0), ('system:user:manage', '用户管理', 'MENU', '/system/user', 0); -- 分配角色权限 INSERT INTO sys_role_permission (role_id, perm_id) SELECT r.id, p.id FROM sys_role r, sys_permission p WHERE r.role_code = 'admin'; INSERT INTO sys_role_permission (role_id, perm_id) SELECT r.id, p.id FROM sys_role r, sys_permission p WHERE r.role_code = 'archive_manager' AND p.perm_code IN ('archive:create', 'archive:view', 'archive:export'); ```

8.2 应用配置文件

application.yml核心配置:

```yaml server: port: 8080 spring: datasource: url: jdbc:mysql://
太原档案数字化服务流程是怎样的?大概需要多少钱?
太原档案数字化服务流程是怎样的?大概需要多少钱?
太原档案数字化服务通常包含需求分析、方案制定、现场整理、扫描加工、数据挂接、验收交付等核心流程,费用根据档案数量、纸张状况、数字化标准等因素综合计算,2026年市场价格范围大致在每页0.5元至2元之间...
2026年08月25日 01:25:04
微信咨询
电话联系
QQ客服
微信咨询一对一服务
服务热线: 028-8744 4417
QQ客服: 2305721818