Java权限结构案例怎么优化

wen java案例 34

本文目录导读:

Java权限结构案例怎么优化

  1. 传统权限结构的问题(需优化的案例)
  2. 优化方案:基于RBAC的权限架构
  3. 高级优化特性
  4. 优化效果对比
  5. 部署建议

针对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())) {
            // 只能删除自己创建的订单
        }
    }
}

主要问题

  1. 权限判断硬编码在业务代码中
  2. 权限检查逻辑散落各处,难以维护
  3. 权限粒度不够灵活
  4. 不支持动态权限配置

优化方案:基于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级别
性能 每次查询数据库 缓存支持
扩展性 支持数据级权限
代码清晰度 权限与业务混合 关注点分离

部署建议

  1. 初期: 先实现RBAC基础模型,使用注解方式
  2. 中期: 引入缓存优化,支持数据级权限
  3. 后期: 实现权限审计、动态权限规则引擎

这个优化方案能够显著提升权限系统的可维护性、灵活性和性能,根据实际业务需求,还可以在此基础上扩展更多的权限控制策略。

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