当前位置: 首页 > 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.lryc.cn/news/602112.html

相关文章:

  • Datawhale AI夏令营 task2 笔记问题汇总收集
  • Python 实现服务器自动故障处理工具:从监控到自愈的完整方案
  • PCS液相色谱柱:专为碱性化合物设计的高性能色谱柱
  • Python 异常 (Exception) 深度解析
  • 项目进度如何控制
  • 新手向:破解VMware迁移难题
  • 元宇宙经济与数字经济的异同:虚实交织下的经济范式对比
  • 【实时Linux实战系列】在实时应用中进行负载均衡
  • PyTorch武侠演义 第二卷:高塔中的注意力秘境 第1章:残卷指引
  • 安宝特案例丨AR+AI赋能轨道交通制造:破解人工装配难题的创新实践
  • 绳子切割 图论
  • RPC 详解
  • 图论(BFS)构造邻接表(运用队列实现搜索)
  • 持续集成CI与自动化测试
  • 鱼皮项目简易版 RPC 框架开发(三)
  • Redis反弹Shell
  • UniappDay04
  • 【跳跃游戏】
  • Vue、微信小程序、Uniapp 面试题整理最新整合版
  • Entity Framework Core (EF Core) 中Database
  • uniapp,uview icon加载太慢了,老是显示叉叉,将远程加载改到本地加载。
  • 设计模式(二十三)行为型:模板方法模式详解
  • 常用设计模式系列(十四)—模板方法模式
  • 开源智能体-JoyAgent集成ollama私有化模型
  • C#与C++交互开发系列(二十六):构建跨语言共享缓存,实现键值对读写与数据同步(实践方案)
  • 基于百度 iframe 框架与语音解析服务的数字人交互系统实现
  • 元宇宙工厂前端新形态:Three.js与WebGL实现3D产线交互的轻量化之路
  • Python系统交互库全解析
  • CentOS 7 安装 dnsmasq 解决nginx无法指定dns的问题
  • 新能源行业B端极简设计:碳中和目标下的交互轻量化实践