当前位置: 首页 > news >正文

Java项目接口权限校验的灵活实现

引言

在Java Web开发中,接口权限校验是保护系统资源安全的关键机制。本文将介绍一种灵活、可配置的接口权限校验方案,通过注解驱动和拦截器实现,既能保证安全性,又能灵活控制哪些接口需要校验。

设计思路

实现方案的核心设计要点:

  1. 注解驱动:使用自定义注解标记需要权限校验的接口
  2. 拦截器机制:在请求处理前进行统一权限校验
  3. 灵活配置:支持方法级和类级配置,可动态调整
  4. 权限缓存:提高权限验证效率

在这里插入图片描述

实现步骤

1. 定义权限校验注解

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface PermissionCheck {/*** 权限标识,支持多个权限(满足任意一个即可)*/String[] value() default {};/*** 是否开启权限校验(默认开启)*/boolean enabled() default true;/*** 逻辑关系:AND-需满足所有权限,OR-满足任意权限*/Logical logical() default Logical.OR;
}public enum Logical {AND, OR
}

2. 实现权限校验拦截器

@Component
public class PermissionInterceptor implements HandlerInterceptor {@Autowiredprivate PermissionService permissionService;@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 如果不是Controller方法直接放行if (!(handler instanceof HandlerMethod)) {return true;}HandlerMethod handlerMethod = (HandlerMethod) handler;Method method = handlerMethod.getMethod();// 获取方法上的注解PermissionCheck methodAnnotation = method.getAnnotation(PermissionCheck.class);// 获取类上的注解PermissionCheck classAnnotation = method.getDeclaringClass().getAnnotation(PermissionCheck.class);// 1. 如果方法上明确关闭权限校验if (methodAnnotation != null && !methodAnnotation.enabled()) {return true;}// 2. 如果类上关闭权限校验且方法未指定if (classAnnotation != null && !classAnnotation.enabled() && (methodAnnotation == null || methodAnnotation.enabled())) {return true;}// 3. 获取当前用户权限User currentUser = getCurrentUser(request);if (currentUser == null) {response.sendError(HttpStatus.UNAUTHORIZED.value(), "用户未登录");return false;}// 4. 获取需要的权限Set<String> requiredPermissions = getRequiredPermissions(methodAnnotation, classAnnotation);// 5. 无需权限校验if (requiredPermissions.isEmpty()) {return true;}// 6. 检查权限boolean hasPermission = checkPermissions(currentUser, requiredPermissions, methodAnnotation != null ? methodAnnotation.logical() : (classAnnotation != null ? classAnnotation.logical() : Logical.OR));if (!hasPermission) {response.sendError(HttpStatus.FORBIDDEN.value(), "权限不足");return false;}return true;}private Set<String> getRequiredPermissions(PermissionCheck methodAnnotation, PermissionCheck classAnnotation) {Set<String> permissions = new HashSet<>();// 方法注解优先if (methodAnnotation != null && methodAnnotation.value().length > 0) {Collections.addAll(permissions, methodAnnotation.value());return permissions;}// 类注解if (classAnnotation != null && classAnnotation.value().length > 0) {Collections.addAll(permissions, classAnnotation.value());}return permissions;}private boolean checkPermissions(User user, Set<String> requiredPermissions, Logical logical) {// 获取用户实际权限(可从缓存中获取)Set<String> userPermissions = permissionService.getUserPermissions(user.getId());if (logical == Logical.AND) {return userPermissions.containsAll(requiredPermissions);} else {return requiredPermissions.stream().anyMatch(userPermissions::contains);}}
}

3. 注册拦截器

@Configuration
public class WebConfig implements WebMvcConfigurer {@Autowiredprivate PermissionInterceptor permissionInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(permissionInterceptor).addPathPatterns("/api/**")  // 拦截API路径.excludePathPatterns("/api/public/**"); // 排除公共接口}
}

4. 权限服务实现

@Service
public class PermissionServiceImpl implements PermissionService {@Autowiredprivate PermissionMapper permissionMapper;@Autowiredprivate CacheManager cacheManager;@Overridepublic Set<String> getUserPermissions(Long userId) {// 从缓存获取Cache cache = cacheManager.getCache("userPermissions");Cache.ValueWrapper wrapper = cache.get(userId);if (wrapper != null) {return (Set<String>) wrapper.get();}// 从数据库查询Set<String> permissions = permissionMapper.selectPermissionsByUserId(userId);// 放入缓存cache.put(userId, permissions);return permissions;}
}

使用示例

1. 类级别权限控制

@RestController
@RequestMapping("/users")
@PermissionCheck(value = {"USER_MANAGE"}, logical = Logical.AND)
public class UserController {// 需要USER_MANAGE权限@GetMappingpublic List<User> listUsers() {// ...}// 不需要权限校验(覆盖类级别设置)@PermissionCheck(enabled = false)@GetMapping("/public")public User getPublicUser() {// ...}
}

2. 方法级别权限控制

@RestController
@RequestMapping("/products")
public class ProductController {// 需要PRODUCT_READ权限@PermissionCheck("PRODUCT_READ")@GetMappingpublic List<Product> listProducts() {// ...}// 需要同时具备PRODUCT_WRITE和PRODUCT_MANAGE权限@PermissionCheck(value = {"PRODUCT_WRITE", "PRODUCT_MANAGE"}, logical = Logical.AND)@PostMappingpublic Product createProduct(@RequestBody Product product) {// ...}
}

3. 公共接口(无需权限)

@RestController
@RequestMapping("/public")
public class PublicController {// 无需任何权限校验@GetMapping("/info")public SystemInfo getSystemInfo() {// ...}
}

进阶优化

1. 动态权限配置

可将权限配置存储在数据库中,实现动态管理:

CREATE TABLE api_permission (id BIGINT PRIMARY KEY AUTO_INCREMENT,api_path VARCHAR(255) NOT NULL,http_method VARCHAR(10) NOT NULL,permission_code VARCHAR(50) NOT NULL,enabled BOOLEAN DEFAULT true,UNIQUE KEY uni_api_method (api_path, http_method)
);

在拦截器中增加数据库权限检查逻辑:

// 在PermissionInterceptor中增加
private boolean checkDynamicPermission(String path, String method) {List<String> requiredPermissions = permissionService.getPermissionsForApi(path, method);if (requiredPermissions.isEmpty()) {return true; // 无配置表示不需要权限}// 检查用户权限...
}

2. 权限缓存策略

使用Redis缓存用户权限数据,提高性能:

@Configuration
public class RedisConfig {@Beanpublic RedisCacheManager cacheManager(RedisConnectionFactory factory) {RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofMinutes(30))  // 30分钟过期.disableCachingNullValues();return RedisCacheManager.builder(factory).cacheDefaults(config).build();}
}@Service
public class RedisPermissionService implements PermissionService {@Autowiredprivate RedisTemplate<String, Set<String>> redisTemplate;@Overridepublic Set<String> getUserPermissions(Long userId) {String key = "user:permissions:" + userId;Set<String> permissions = redisTemplate.opsForSet().members(key);if (permissions == null || permissions.isEmpty()) {// 从数据库加载permissions = permissionMapper.selectPermissionsByUserId(userId);if (!permissions.isEmpty()) {redisTemplate.opsForSet().add(key, permissions.toArray(new String[0]));redisTemplate.expire(key, 30, TimeUnit.MINUTES);}}return permissions;}
}

方案对比

实现方式优点缺点适用场景
拦截器+注解灵活、非侵入、配置简单无法动态修改中小型项目
动态数据库配置可动态调整、集中管理增加数据库访问、实现复杂大型复杂系统
AOP实现解耦彻底、可复用性高配置复杂、学习曲线陡峭需要高度解耦的系统

总结

本文介绍了一种基于注解和拦截器的接口权限校验方案,具有以下特点:

  1. 灵活配置:通过注解控制每个接口的权限要求
  2. 非侵入式:不影响业务逻辑代码
  3. 层次分明:支持类级别和方法级别的权限控制
  4. 易于扩展:可结合数据库实现动态权限管理
  5. 性能优化:通过缓存减少权限查询开销

通过合理的权限校验实现,可以大大提高系统的安全性,同时保持代码的整洁和可维护性。根据项目需求,可以选择合适的实现方式和优化策略。

提示:在实际项目中,建议结合Spring Security或Shiro等安全框架,可以更全面地解决认证授权问题。本文方案适用于需要轻量级权限控制的场景。

http://www.dtcms.com/a/302588.html

相关文章:

  • AI学习之Cursor项目实战
  • ICPC 2024 网络赛(I)
  • 【大模型LLM】梯度累积(Gradient Accumulation)原理详解
  • linux I2C设备AW2013驱动示例
  • rhel网卡配置文件、网络常用命令、网卡名称优化和模拟不同网络区域通信
  • 服务器中的防火墙设置需要打开吗
  • 服务器查日志太慢,试试grep组合拳
  • 利用frp实现内网穿透功能(服务器)Linux、(内网)Windows
  • CentOS7 安装和配置教程
  • RF随机森林分类预测+特征贡献SHAP分析,通过特征贡献分析增强模型透明度,Matlab代码实现,引入SHAP方法打破黑箱限制,提供全局及局部双重解释视角
  • 论文:M矩阵
  • 高可用集群Keepalived、Redis、NoSQL数据库Redis基础管理
  • 常用设计模式系列(十四)—模板方法模式
  • 在 CentOS 上安装 FFmpeg
  • 行业案例:杰和科技为智慧教育构建数字化硬件底座
  • UML类图--基于大话设计模式
  • 【设计模式】状态模式 (状态对象(Objects for States))
  • NBIOT模块 BC28通过MQTT协议连接到电信云
  • Google Chrome V8< 13.7.120 沙箱绕过漏洞
  • 设计模式(二十三)行为型:模板方法模式详解
  • 从 “看天吃饭” 到 “精准可控”:边缘计算网关如何引爆智慧农业种植变革?
  • 新手向:破解VMware迁移难题
  • 解放io_uring编程:liburing实战指南与经典cat示例解析
  • Unity_UI_NGUI_组合控件2
  • Rust实战:AI与机器学习自动炒饭机器学习
  • puppeteer 系列模块的系统性、详细讲解
  • Ubuntu系统完整配置教程
  • InfluxDB 与 HTTP 协议交互进阶(一)
  • 设计模式实战:自定义SpringIOC(理论分析)
  • 无界设计新生态:Penpot开源平台与cpolar的云端协同创新实践