开发者

Spring Security方法级安全控制@PreAuthorize注解的灵活运用小结

目录
  • 1. 前言
  • 2. @PreAuthorize 注解简介
  • 3. @PreAuthorize 核心原理解析
    • 拦截与表达式求值
    • SpEL 表达式
    • 自定义扩展
  • 注解应用实战
    • ❶ 基础权限校验
    • ❷ 参数级权限控制
    • ❸ 动态业务规则集成
    • ❹ 复合条件表达式
    • ❺ 返回值后校验
    • ❻ 参数预处理
  • 结语

    1. 前言

    在实js际项目中,安全控制不编程仅体现在 URL 拦截层面,方法级安全控制也越来越受到重视。Spring Security 提供了多种方式实现方法级安全,Spring Security 通过方法注解体系,这种细粒度控制使得我们能够在方法调用前、调用后,甚至返回值处理阶段实施安全检查,真正成为开发者保护服务接口的重要手段

    相信小伙伴通过前面章节的学习,发现了博主在方法上进行角色和菜单资源验证的时候使用的一个注解:@PreAuthorize,那么本章节博主将带着大家剖析 @PreAuthorize 注解的核心原理、SpEL 表达式机制,并通过的示例代码演示如何在实际项目中灵活运用该注解实现细粒度的权限控制。

    2. @PreAuthorize 注解简介

    @PreAuthorize 注解可以在方法执行前对传入的参数、当前用户信息、认证状态等进行校验,从而决定是否允许方法执行。常见使用场景包括:

    • 限制某个接口或方法只允许特定角色访问;
    • 根据方法参数和认证信息动态判断权限;
    • 调用自定义的权限判断逻辑(例如上一个章节中结合自定义 PermissionEvaLuator);
    • 限制某个接口或方法只允许特定角色访问;
    • 根据方法参数和认证信息动态判断权限;
    • 调用自定义的权限判断逻辑(例如上一个章节中结合自定义 PermissionEvaluator);

    Spring Security 内部通过 AOP 拦截被 @PreAuthorize 修饰的方法,并利用 Spring Expression Language(SpEL)对注解中定义的表达式进行求值。只有当表达式求值结果为 true 时,方法才会执行,否则会抛出拒绝访问异常。

    3. @PreAuthorize 核心原理解析

    Spring Security 开启方法级安全控制实际上非常简单,只需要在 @Cjsonfiguration 配置类中添加 @EnableMethodSecurity

    @Configuration
    //开启方法级的安全控制
    @EnableMethodSecurity
    public class AbacSecurityConfig {
    	//....
    }

    方法授权可以分为方法前授权方法后授权的组合,看下面的例子

    @Service
    public class MyCustomerService {
        @PreAuthorize("hasAuthority('permission:read')")
        @PostAuthorize("returnObject.owner == authentication.name")
        public Customer readCustomer(String id) { ... }
    }

    当方法安全性被激活时,对 MyCustomerService#readCustomer 的调用流程如下(官方流程图):

    Spring Security方法级安全控制@PreAuthorize注解的灵活运用小结

    流程解析

    Spring AOP 为 readCustomer 调用其代理方法。它调用与AuthorizationManagerBeforeMethodInterceptor切入点匹配的@PreAuthorize

    拦截器调用 PreAuthorizeAuthorizationManager#check

    授权python管理器使用 MethodSecurityExpressionHandler 解析注释的 SpEL表达式,并从包含EvaluationContext和MethodSecurityExpressionRoot的Supplier构造对应的MethodInvocation。

    拦截器使用此上下文来评估表达式,它从Authentication读取Supplier,并检查其权限集合中是否有permission:read

    如果评估通过,那么Spring AOP继续调用该方法

    如果不通过,拦截器发布一个AuthorizationDeniedEvent并抛出一个AccessDeniedException,ExceptionTranslationFilter捕获并向响应返回一个403状态码

    方法返回后,Spring AOP 调用与切入点匹配AuthorizationManagerAfterMethodInterceptor的,操作与上面相同,但是@PostAuthorizePostAuthorizeAuthorizationManager

    如果评估通过(在这种情况下,返回值属于登录用户),则处理继续正常进行

    如果不通过,拦截器将发布一个AuthorizationDeniedEvent并抛出一个AccessDeniedException,然后捕获ExceptionTranslationFilter并向响应返回 403 状态代码

    拦截与表达式求值

    从上述官方介绍的工作流程来看,我们可以简单总结为:

    Spring Security 在启用方法级安全时,会在应用上下文中配置一个 MethodSecurityInte编程rceptor(基于 AOP 实现)。当被 @PreAuthorize 修饰的方法被调用时:

    • 拦截器捕获方法调用,并构造 EvaluationContext,上下文中包含认证信息、方法参数等数据
    • 使用 MethodSecurityExpressionHandler 将注解中的 SpEL 表达式求值,判断是否满足访问条件
    • 如果表达式结果为 false,则抛出 AccessDeniedException 否则放行执行方法

    Spring Security方法级安全控制@PreAuthorize注解的灵活运用小结

    SpEL 表达式

    @PreAuthorize 注解的值是一个 SpEL 表达式,可以引用以下内置变量:

    • authentication:当前用户的认证对象。
    • principal:当前认证用户的主体信息(通常为 UserDetails 对象)。
    • #root:表达式根对象。
    • 方法参数:可以通过 #paramName 或 #p0 访问方法参数。

    如下代码

    @PreAuthorize("hasRole('ADMIN') and #id > 10")
    public void deleteUser(Long id) { ... }

    表示只有当前用户拥有 ADMIN 角色且方法参数 id 大于 10 时,才能执行该方法。

    自定义扩展

    通过自定义 MethodSecurityExpressionHandler 和 PermissionEvaluator,可以扩展 @PreAuthorize 表达式功能。具体可以查阅上个章节ABAC属性权限模型实战开发

    注解应用实战

    下面通过一些简单示例,演示如何配置 Spring Security 方法级安全

    ❶ 基础权限校验

    @PreAuthorize("hasRole('ADMIN')")
    public void deleteResource(Long resourceId){
        // 方法实现
    }
    @PreAuthorize("hasAuthority('RESOURCE_APPROVE')")
    public void approveRequest(Request request){
        // 审批逻辑
    }

    ❷ 参数级权限控制

    // 校验创建者匹配
    @PreAuthorize("#article.createdBy == authentication.name")
    public void updateArticle(Article article){
        // 更新操作
    }
    // 参数过滤示例
    @PreAuthorize("@permissionChecker.hasAccess(#userId, 'EDIT')")
    public void editUserProfile(Long userId, Profile profile){
        // 编辑逻辑
    }

    ❸ 动态业务规则集成

    如没有了解的小伙伴,建议查阅博主上一章节内容(这里仅演示如何配置@PreAuthorize):

    最新Spring Security实战教程(六)最新Spring Security实战教程(六)基于数据库的ABAC属性权限模型实战开发

    public class DocumentPermissionEvaluator {
        public boolean checkAccess(Long docId, String permission) {
            // 自定义文档权限校验逻辑
        }
    }
    // 在SpEL中调用自定义评估器
    @PreAuthorize("@documentPermissionEvaluator.checkAccess(#docId, 'WRITE')")
    public void updateDocument(Long docId, String content){
        // 文档更新
    }

    ❹ 复合条件表达式

    // 组合多个条件
    @PreAuthorize("hasRole('ADMIN') or (#user.department == authentication.user.department and hasAuthority('DEPT_ADMIN'))")
    public void manageUser(User user){
        // 用户管理逻辑
    }

    ❺ 返回值后校验

    @PostAuthorize("returnObject.owner == authentication.name")
    public Document getConfidentialDocument(Long id){
        // 获取文档逻辑
    }

    ❻ 参数预处理

    @PreFilter("filterObject.owner == authentication.name")
    public void BATchProcess(List<Document> documents){
        // 仅处理当前用户拥有的文档
    }

    结语

    通过本章节方法级安全控制的介绍,相信大家已经能通过灵活运用表达式语言和自定义扩展,让我们可以在保证系统安全性的同时,维持代码的优雅与可维护性!希望这章节文章对你在 Spring Security 方法级安全控制的实践中提供帮助和启发!

    到此这篇关于Spring Security方法级安全控制@PreAuthorize注解的灵活运用小结的文章就介绍到这了,更多相关Spring Security @PreAuthorize注解内容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.devze.com)!

    0

    上一篇:

    下一篇:

    精彩评论

    暂无评论...
    验证码 换一张
    取 消

    最新开发

    开发排行榜