1. 前言
在实际项目中,安全控制不仅体现在 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
开启方法级安全控制实际上非常简单,只需要在 @configuration
配置类中添加 @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 aop 为 readcustomer 调用其代理方法。它调用与authorizationmanagerbeforemethodinterceptor切入点匹配的@preauthorize
拦截器调用 preauthorizeauthorizationmanager#check
授权管理器使用 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
在启用方法级安全时,会在应用上下文中配置一个 methodsecurityinterceptor
(基于 aop 实现)。当被 @preauthorize
修饰的方法被调用时:
- 拦截器捕获方法调用,并构造
evaluationcontext
,上下文中包含认证信息、方法参数等数据 - 使用
methodsecurityexpressionhandler
将注解中的spel
表达式求值,判断是否满足访问条件 - 如果表达式结果为 false,则抛出
accessdeniedexception
否则放行执行方法
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注解内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论