本文目录导读:

针对Java权限结构的优化,我推荐一个基于RBAC(基于角色的访问控制)模型的优化方案,下面我通过一个具体的案例来展示从传统实现到优化方案的全过程。
传统权限结构的问题(需优化的案例)
原始代码示例
// 传统实现:硬编码权限判断
public class OrderService {
public void deleteOrder(Long orderId, User user) {
// 问题1:权限逻辑散落在业务代码中
if (!user.getRole().equals("ADMIN") &&
!user.getRole().equals("SUPER_ADMIN")) {
throw new PermissionDeniedException("无权限删除订单");
}
// 问题2:权限判断冗余
if (user.getPermissions() != null &&
user.getPermissions().contains("ORDER:DELETE")) {
// 执行删除逻辑
}
// 问题3:无法灵活配置权限粒度
if (user.getDepartment().equals("SALES") &&
order.getCreatorId().equals(user.getId())) {
// 只能删除自己创建的订单
}
}
}
主要问题
- 权限判断硬编码在业务代码中
- 权限检查逻辑散落各处,难以维护
- 权限粒度不够灵活
- 不支持动态权限配置
优化方案:基于RBAC的权限架构
数据库表结构设计
-- 用户表
CREATE TABLE sys_user (
id BIGINT PRIMARY KEY,
username VARCHAR(50),
status TINYINT DEFAULT 1
);
-- 角色表
CREATE TABLE sys_role (
id BIGINT PRIMARY KEY,
role_name VARCHAR(50),
role_code VARCHAR(50) UNIQUE,
status TINYINT DEFAULT 1
);
-- 权限表(资源权限)
CREATE TABLE sys_permission (
id BIGINT PRIMARY KEY,
permission_name VARCHAR(50),
permission_code VARCHAR(100) UNIQUE, -- 如: order:delete
type VARCHAR(20), -- menu/button/api
parent_id BIGINT,
sort_order INT
);
-- 用户角色关联表
CREATE TABLE sys_user_role (
user_id BIGINT,
role_id BIGINT,
PRIMARY KEY (user_id, role_id)
);
-- 角色权限关联表
CREATE TABLE sys_role_permission (
role_id BIGINT,
permission_id BIGINT,
PRIMARY KEY (role_id, permission_id)
);
权限注解设计
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface PreAuthorize {
String value(); // 权限表达式,如 "hasPermission('order:delete')"
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RequiresPermission {
String[] value();
Logical logical() default Logical.AND; // AND/OR 逻辑
}
核心权限服务
@Service
public class PermissionService {
@Autowired
private UserRoleMapper userRoleMapper;
@Autowired
private RolePermissionMapper rolePermissionMapper;
public boolean hasPermission(Long userId, String permissionCode) {
// 1. 查询用户角色
List<Long> roleIds = userRoleMapper.findRoleIdsByUserId(userId);
if (roleIds.isEmpty()) {
return false;
}
// 2. 查询角色权限(使用缓存)
Set<String> permissions = getPermissionsByRoles(roleIds);
// 3. 检查权限
return permissions.contains(permissionCode);
}
@Cacheable(value = "user_permissions", key = "#roleIds")
public Set<String> getPermissionsByRoles(List<Long> roleIds) {
// 批量查询角色权限
List<SysPermission> permissions =
rolePermissionMapper.findPermissionsByRoleIds(roleIds);
return permissions.stream()
.map(SysPermission::getPermissionCode)
.collect(Collectors.toSet());
}
}
AOP权限切面
@Aspect
@Component
public class PermissionAspect {
@Autowired
private PermissionService permissionService;
@Around("@annotation(requiresPermission)")
public Object checkPermission(ProceedingJoinPoint joinPoint,
RequiresPermission requiresPermission) throws Throwable {
// 获取当前用户
User currentUser = SecurityContextHolder.getCurrentUser();
// 检查权限
for (String permission : requiresPermission.value()) {
boolean hasPerm = permissionService.hasPermission(
currentUser.getId(), permission);
if (requiresPermission.logical() == Logical.AND && !hasPerm) {
throw new PermissionDeniedException("无权限执行此操作");
}
if (requiresPermission.logical() == Logical.OR && hasPerm) {
return joinPoint.proceed();
}
}
return joinPoint.proceed();
}
}
优化后的业务代码
@Service
public class OrderService {
@Autowired
private PermissionService permissionService;
// 方式1:使用注解
@RequiresPermission(value = {"order:delete"}, logical = Logical.AND)
public void deleteOrder(Long orderId) {
// 业务逻辑,不再包含权限判断
orderRepository.deleteById(orderId);
}
// 方式2:编程式权限检查
public void updateOrder(Order order) {
// 更复杂的权限逻辑
if (!permissionService.hasPermission(
SecurityContextHolder.getCurrentUser().getId(),
"order:update")) {
throw new PermissionDeniedException("无权限修改订单");
}
// 数据级权限
if (order.getStatus() == OrderStatus.PAID &&
!permissionService.hasPermission(
SecurityContextHolder.getCurrentUser().getId(),
"order:update:paid")) {
throw new PermissionDeniedException("无权修改已支付订单");
}
// 执行业务逻辑
orderRepository.save(order);
}
}
高级优化特性
数据级权限控制
// 数据权限注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DataPermission {
Class<?> entityClass();
String column(); // 部门ID或其他维度
}
// 数据权限过滤
public class DataPermissionAspect {
@Around("@annotation(dataPermission)")
public Object addDataFilter(ProceedingJoinPoint joinPoint,
DataPermission dataPermission) {
// 获取用户数据权限范围
User user = SecurityContextHolder.getCurrentUser();
DataScope scope = user.getDataScope(); // ALL/DEPT/SELF
// 动态添加SQL过滤条件
String filterSql = buildDataFilterSql(scope, user);
DataScopeContext.set(filterSql);
try {
return joinPoint.proceed();
} finally {
DataScopeContext.clear();
}
}
}
权限缓存优化
@Configuration
public class PermissionCacheConfig {
@Bean
public CacheManager permissionCacheManager() {
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofMinutes(30)) // 30分钟过期
.disableCachingNullValues();
return RedisCacheManager.builder(redisTemplate)
.cacheDefaults(config)
.build();
}
}
// 权限变更时清除缓存
@Service
public class PermissionManageService {
@Autowired
private CacheManager cacheManager;
@Transactional
public void updateUserRole(Long userId, List<Long> roleIds) {
// 更新用户角色
userRoleMapper.updateUserRoles(userId, roleIds);
// 清除该用户的权限缓存
cacheManager.getCache("user_permissions").evict(userId);
}
}
性能优化建议
// 1. 权限表达式缓存
@Component
public class PermissionExpressionCache {
private LoadingCache<String, Boolean> permissionCache = Caffeine.newBuilder()
.maximumSize(10000)
.expireAfterWrite(5, TimeUnit.MINUTES)
.build(key -> {
// 解析权限表达式并判断
return evaluatePermission(key);
});
public boolean hasPermission(String expression) {
return permissionCache.get(expression);
}
}
// 2. 批量权限检查
@RequiresPermissions({
"order:view",
"order:export"
}, logical = Logical.OR)
public void exportOrders() {
// 导出订单
}
优化效果对比
| 特性 | 优化前 | 优化后 |
|---|---|---|
| 权限配置方式 | 硬编码 | 数据库配置 + 注解 |
| 维护成本 | 高(修改需改代码) | 低(后台可配置) |
| 权限粒度 | 角色级别 | 资源/API级别 |
| 性能 | 每次查询数据库 | 缓存支持 |
| 扩展性 | 差 | 支持数据级权限 |
| 代码清晰度 | 权限与业务混合 | 关注点分离 |
部署建议
- 初期: 先实现RBAC基础模型,使用注解方式
- 中期: 引入缓存优化,支持数据级权限
- 后期: 实现权限审计、动态权限规则引擎
这个优化方案能够显著提升权限系统的可维护性、灵活性和性能,根据实际业务需求,还可以在此基础上扩展更多的权限控制策略。