欢迎阅读 Spring Security 实战干货 系列文章 。在上一篇 基于配置的接口角色访问控制 咱们讲解了如何经过 javaConfig 的方式配置接口的角色访问控制。其实还有一种更加灵活的配置方式 基于注解 。今天咱们就来探讨一下。DEMO 获取方式在文末。html
Spring Security 基于注解的安全认证是经过在相关的方法上进行安全注解标记来实现的。java
咱们能够在任何 @Configuration
实例上使用 @EnableGlobalMethodSecurity
注解来启用全局方法安全注解功能。该注解提供了三种不一样的机制来实现同一种功能,因此咱们单独开一章进行探讨。spring
@Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME) @Target(value = { java.lang.annotation.ElementType.TYPE }) @Documented @Import({ GlobalMethodSecuritySelector.class }) @EnableGlobalAuthentication @Configuration public @interface EnableGlobalMethodSecurity { /** * 基于表达式进行方法访问控制 */ boolean prePostEnabled() default false; /** * 基于 @Secured 注解 */ boolean securedEnabled() default false; /** * 基于 JSR-250 注解 */ boolean jsr250Enabled() default false; boolean proxyTargetClass() default false; int order() default Ordered.LOWEST_PRECEDENCE; }
@EnableGlobalMethodSecurity
源码中提供了 prePostEnabled
、securedEnabled
和 jsr250Enabled
三种方式。当你开启全局基于注解的方法安全功能时,也就是使用 @EnableGlobalMethodSecurity
注解时咱们须要选择使用这三种的一种或者其中几种。咱们接下来将分别介绍它们。express
若是你在 @EnableGlobalMethodSecurity
设置 prePostEnabled
为 true
,则开启了基于表达式的方法安全控制。经过表达式运算结果的布尔值来决定是否能够访问(true
开放, false
拒绝 )。
有时您可能须要执行开启 prePostEnabled
复杂的操做。对于这些实例,您能够扩展 GlobalMethodSecurityConfiguration
,确保子类上存在@EnableGlobalMethodSecurity(prePostEnabled = true)
。例如,若是要提供自定义 MethodSecurityExpressionHandler
:编程
@EnableGlobalMethodSecurity(prePostEnabled = true) public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration { @Override protected MethodSecurityExpressionHandler createExpressionHandler() { // ... create and return custom MethodSecurityExpressionHandler ... return expressionHandler; } }
上面示例属于高级操做,通常没有必要。不管是否继承GlobalMethodSecurityConfiguration
都将会开启四个注解。 @PreAuthorize
和 @PostAuthorize
侧重于方法调用的控制;而 @PreFilter
和 @PostFilter
侧重于数据的控制。segmentfault
在标记的方法调用以前,经过表达式来计算是否能够受权访问。接下来我来总结如下经常使用的表达式。安全
SecurityExpressionOperations
接口的表达式,也就是咱们在上一文的 javaConfig
配置。示例: @PreAuthorize("hasRole('ADMIN')")
必须拥有 ROLE_ADMIN
角色。UserDetails
的表达式,此表达式用以对当前用户的一些额外的限定操做。示例:@PreAuthorize("principal.username.startsWith('Felordcn')")
用户名开头为 Felordcn
的用户才能访问。SpEL
表达式处理。关于 SpEL
表达式可参考官方文档。或者经过关注公众号:Felordcn 来获取相关资料。 示例: @PreAuthorize("#id.equals(principal.username)")
入参 id
必须同当前的用户名相同。在标记的方法调用以后,经过表达式来计算是否能够受权访问。该注解是针对 @PreAuthorize
。区别在于先执行方法。然后进行表达式判断。若是方法没有返回值实际上等于开放权限控制;若是有返回值实际的结果是用户操做成功可是得不到响应。微信
基于方法入参相关的表达式,对入参进行过滤。分页慎用!该过程发生在接口接收参数以前。 入参必须为 java.util.Collection
且支持 remove(Object)
的参数。若是有多个集合须要经过 filterTarget=<参数名>
来指定过滤的集合。内置保留名称 filterObject
做为集合元素的操做名来进行评估过滤。 ide
样例:测试
// 入参为Collection<String> ids 测试数据 ["Felordcn","felord","jetty"] // 过滤掉 felord jetty 为 Felordcn @PreFilter(value = "filterObject.startsWith('F')",filterTarget = "ids") // 若是 当前用户持有 ROLE_AD 角色 参数都符合 不然 过滤掉不是 f 开头的 // DEMO 用户不持有 ROLE_AD 角色 故而 集合只剩下 felord @PreFilter("hasRole('AD') or filterObject.startsWith('f')")
和@PreFilter
不一样的是, 基于返回值相关的表达式,对返回值进行过滤。分页慎用!该过程发生接口进行数据返回以前。 相关测试与 @PreFilter
类似,参见文末提供的 DEMO。
若是你在 @EnableGlobalMethodSecurity
设置 securedEnabled
为 true
,就开启了角色注解 @Secured
,该注解功能要简单的多,默认状况下只能基于角色(默认须要带前缀 ROLE_
)集合来进行访问控制决策。
该注解的机制是只要其声明的角色集合(value
)中包含当前用户持有的任一角色就能够访问。也就是 用户的角色集合和 @Secured
注解的角色集合要存在非空的交集。 不支持使用 SpEL 表达式进行决策。
启用 JSR-250 安全控制注解,这属于 JavaEE 的安全规范(现为 jakarta 项目)。一共有五个安全注解。若是你在 @EnableGlobalMethodSecurity
设置 jsr250Enabled
为 true
,就开启了 JavaEE 安全注解中的如下三个:
@Secured
同样。今天讲解了 Spring Security 另外一种基于注解的静态配置。相比较基于 javaConfig
的方式要灵活一些、粒度更细、基于 SpEL 表达式能够实现更增强大的功能。可是这两种的方式仍是基于编程的静态方式,具备必定的局限性。更加灵活的方式应该是动态来处理用户的角色和资源的映射关系,这是之后咱们将要解决的问题。
本次的 DEMO 可经过 关注微信公众号:Felordcn 回复 ss09 获取。
关注公众号:Felordcn 获取更多资讯