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

SpringBoot | 越权和数据权限控制的一种实现方案

CodingTechWork

引言

  在基于 Java 的开发中,通常使用 Spring 框架来实现权限管理、注解和切面编程。为了实现您提到的权限控制逻辑,我们可以按照以下步骤来实现注解、切面以及权限检查。以下是一个详细的实现方案:

定义权限注解

首先,我们需要定义一个自定义的注解 @PermissionCheck,这个注解会包含操作类型(CRUD)、资产ID和资产名称作为入参。可以参考以下代码来定义这个注解:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
// 该注解作用于方法
@Target(ElementType.METHOD)  
// 运行时生效
@Retention(RetentionPolicy.RUNTIME)  
public @interface PermissionCheck {// 操作类型,默认为 READString operation() default "READ";  // 资产 IDString assetId() default ""; // 资产名称String assetName() default "";  // 还可以扩展其他的字段... ...
}

在 Controller 方法中使用注解

然后,在需要进行权限验证的 Controller 方法中,我们可以使用 @PermissionCheck 注解来指定需要的操作类型、资产 ID 和资产名称。

@RestController
@RequestMapping("/assets")
public class AssetController {// 只允许读取权限@PermissionCheck(operation = "READ", assetId = "asset123", assetName = "assetA")@GetMapping("/view")public Asset viewAsset(@RequestParam String assetId) {// 业务逻辑return assetService.getAssetById(assetId);}// 只允许创建操作@PermissionCheck(operation = "CREATE", assetId = "asset124", assetName = "assetB")@PostMapping("/create")public Asset createAsset(@RequestBody Asset asset) {// 业务逻辑return assetService.createAsset(asset);}
}

切面(Aspect)实现权限验证

接下来,我们要创建一个切面类,利用 AOP(面向切面编程)拦截标记了 @PermissionCheck 注解的方法。通过切面,我们可以获取用户的角色信息,判断用户是否有权限进行特定操作,并根据需要抛出异常。

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;@Aspect
@Component
public class PermissionAspect {// 用于获取当前用户的权限信息@Autowiredprivate UserService userService;  // 切入点,拦截标注 @PermissionCheck 的方法@Pointcut("@annotation(permissionCheck)")  public void checkPermission(PermissionCheck permissionCheck) {}// 在方法执行前进行权限校验@Before("checkPermission(permissionCheck)")  public void checkPermissionBefore(PermissionCheck permissionCheck) throws Exception {String operation = permissionCheck.operation();String assetId = permissionCheck.assetId();String assetName = permissionCheck.assetName();// 获取当前登录用户的 IDString userId = SecurityContextHolder.getContext().getAuthentication().getName();// 获取当前用户的角色:可以是只读或正常用户等User user = userService.getUserById(userId);if ("READ".equals(operation) && !user.isReadOnly()) {// 如果是只读用户但操作不是 READ,抛出异常throw new PermissionException("只读用户不允许进行此操作");}// 检查操作权限:只允许特定用户对特定资产进行 CREATE/UPDATE/DELETE 操作if (!"READ".equals(operation)) {if (!hasPermission(userId, assetId, assetName)) {throw new PermissionException("用户没有访问该资产的权限");}}}private boolean hasPermission(String userId, String assetId, String assetName) {// 查询数据库,检查当前用户是否对给定的资产 ID 或资产名称有权限return userService.hasAssetPermission(userId, assetId, assetName);}
}

4. 用户权限服务实现

在上面的切面代码中,我们调用了 userService 来判断当前用户是否有权限操作某个资产。UserService 需要实现以下逻辑:

@Service
public class UserService {// 根据用户 ID 查询用户信息,判断是否为只读用户public User getUserById(String userId) {// 假设从数据库获取用户信息return userRepository.findById(userId).orElseThrow(() -> new UserNotFoundException("用户不存在"));}// 查询用户是否有访问某个资产的权限public boolean hasAssetPermission(String userId, String assetId, String assetName) {// 这里我们可以查询数据库,检查当前用户是否有对应资产的权限return permissionRepository.existsByUserIdAndAssetIdOrAssetName(userId, assetId, assetName);}
}

异常处理

当权限不满足时,我们需要抛出自定义的异常并进行全局处理。

public class PermissionException extends RuntimeException {public PermissionException(String message) {super(message);}
}@ControllerAdvice
public class GlobalExceptionHandler {@ExceptionHandler(PermissionException.class)@ResponseStatus(HttpStatus.FORBIDDEN)public ResponseEntity<String> handlePermissionException(PermissionException ex) {return ResponseEntity.status(HttpStatus.FORBIDDEN).body(ex.getMessage());}
}

其他相关注意事项

  • 只读用户的限制:在 checkPermissionBefore 方法中,我们通过判断 operation 字段来确定是否是只读用户操作。若是只读用户,但操作尝试修改数据(CREATE/UPDATE/DELETE),则会抛出异常。
  • 权限查询优化:在实际项目中,查询数据库是否有权限时,可以使用缓存来提高查询性能,避免频繁的数据库访问。
  • 全局异常处理:通过 @ControllerAdvice 和自定义异常类,能够确保权限错误的响应更加友好和统一。

总结

通过以上的实现,我们使用了自定义注解、切面编程和用户权限服务的组合来对方法进行权限控制,确保只读用户无法进行修改操作,同时判断其他用户是否有权限访问特定的资产。这样的方法可以灵活扩展,方便在大型系统中进行细粒度的权限控制。

http://www.lqws.cn/news/511741.html

相关文章:

  • spring01-简介
  • “苏超”拉动周末消费,抖音生活服务:比赛城市迎来普遍消费上涨
  • 鸿蒙 FolderStack 组件全解析:折叠屏悬停布局开发指南
  • 【源码】Reactive 源码
  • c++ 空指针,悬挂指针(悬空指针),野指针
  • 总结汇报思路
  • 重点解析(软件工程)
  • 使用markRaw实例化echarts对象
  • RAG实战 第三章:知识库构建与管理
  • OSS安全合规实战:金融行业敏感数据加密+KMS自动轮转策略(满足等保2.0三级要求)
  • 宝塔服务器调优工具 1.1(Opcache优化)
  • 跟着chrome面板优化页面性能
  • 中断控制与实现
  • 《C++》命名空间简述
  • AutoGPT,自主完成复杂任务
  • 安卓9.0系统修改定制化____安卓9.0修改 默认开启开发者选项与usb调试的操作步骤解析 十一
  • 2025.6.24总结
  • # Python中等于号的使用
  • 创建首个 Spring Boot 登录项目
  • Linux零基础快速入门到精通
  • 大模型本地部署,拥有属于自己的ChatGpt
  • Vue 英雄列表搜索与排序功能实现
  • Verilog基础:编译指令`default_nettype
  • Harmony状态管理@Event
  • ubuntu16编译paho.mqtt.c 及 paho.mqtt.cpp编译问题
  • 屠龙刀策略
  • Web攻防-CSRF跨站请求伪造Referer同源Token校验复用删除置空联动上传或XSS
  • 统计学纯基础(1)
  • C++ 快速回顾(一)
  • 学习记录:DAY33