SpringBoot越权和数据权限控制的实现方案(最新整理)

 更新时间:2025年06月27日 10:56:32   作者:Andya_net  
文章介绍通过自定义注解@PermissionCheck、切面编程和用户权限服务实现Java权限控制,限制只读用户操作,优化数据库查询并统一异常处理,确保系统安全与扩展性,本文给大家介绍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 {
	// 操作类型,默认为 READ
    String operation() default "READ";  
    // 资产 ID
    String 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 {
	// 用于获取当前用户的权限信息
    @Autowired
    private 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();
        // 获取当前登录用户的 ID
        String 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 和自定义异常类,能够确保权限错误的响应更加友好和统一。

总结

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

到此这篇关于SpringBoot越权和数据权限控制的实现方案(最新整理)的文章就介绍到这了,更多相关SpringBoot 权限控制内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 如何在Spring Boot框架中使用拦截器实现URL限制

    如何在Spring Boot框架中使用拦截器实现URL限制

    在Spring Boot框架中,您可以使用拦截器(Interceptor)来控制限制URL列表,本文通过一个简单的示例给大家介绍Spring Boot 拦截器实现URL限制的操作方法,感兴趣的朋友跟随小编一起看看吧
    2023-08-08
  • 菜鸟学习java设计模式之单例模式

    菜鸟学习java设计模式之单例模式

    这篇文章主要为大家详细介绍了java设计模式之单例模式的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-11-11
  • SpringMVC中的HandlerMapping和HandlerAdapter详解

    SpringMVC中的HandlerMapping和HandlerAdapter详解

    这篇文章主要介绍了SpringMVC中的HandlerMapping和HandlerAdapter详解,在Spring MVC中,HandlerMapping(处理器映射器)用于确定请求处理器对象,请求处理器可以是任何对象,只要它们使用了@Controller注解或注解@RequestMapping,需要的朋友可以参考下
    2023-08-08
  • Java IO流总结

    Java IO流总结

    文章系统讲解了Java IO流的核心知识点,包括字节流与字符流的分类及操作、缓冲流的高效读写、转换流处理编码问题、序列化流实现对象持久化、打印流控制台输出、压缩流处理文件打包,感兴趣的朋友跟随小编一起看看吧的相关资料
    2025-08-08
  • 10个SpringBoot框架内置的实用功能详解

    10个SpringBoot框架内置的实用功能详解

    在 Spring Boot 开发中,框架内置的诸多实用功能犹如一把把利刃,能让开发者在项目的各个阶段都事半功倍,这些功能无需额外集成,通过简单配置或编码即可快速实现常见需求,下面将为你深入解析一系列极具价值的内置功能,需要的朋友可以参考下
    2025-06-06
  • 利用Java如何实现将二维数组转化为链式储存

    利用Java如何实现将二维数组转化为链式储存

    链式结构不要求逻辑上相邻的节点在物理位置上也相邻,节点间的逻辑关系是由附加的指针字段表示的,通常借助于程序设计中的指针结构来实现,这篇文章主要给大家介绍了关于利用Java如何实现将二维数组转化为链式储存的相关资料,需要的朋友可以参考下
    2021-12-12
  • 解决mybatisPlus null 值更新的问题

    解决mybatisPlus null 值更新的问题

    这篇文章主要介绍了解决mybatisPlus null 值更新的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-02-02
  • MyBatis中#{} 和 ${} 的区别和动态 SQL详解

    MyBatis中#{} 和 ${} 的区别和动态 SQL详解

    这篇文章主要介绍了MyBatis中#{}和${}的区别,包括参数传递、安全性、性能等方面,然后详细介绍了如何使用#{}和${}进行排序、模糊查询、动态SQL、数据库连接池等操作,最后,总结了注解方式的动态SQL,感兴趣的朋友跟随小编一起看看吧
    2024-11-11
  • java9中gc log参数迁移

    java9中gc log参数迁移

    本篇文章给大家详细讲述了java9中gc log参数迁移的相关知识点,对此有需要的朋友可以参考学习下。
    2018-03-03
  • springboot vue完成编辑页面发送接口请求功能

    springboot vue完成编辑页面发送接口请求功能

    这篇文章主要为大家介绍了springboot+vue完成编辑页发送接口请求功能,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-05-05

最新评论