当前位置: 首页 > 科技观察

SpringSecurity实战干货:基于注解的接口角色权限访问控制

时间:2023-03-11 22:58:42 科技观察

1.前言欢迎阅读SpringSecurity实战干货系列文章。在上一篇文章基于配置的接口角色访问控制中,我们讲解了如何通过javaConfig配置接口角色访问控制。其实还有一种更灵活的基于注解的配置方式。今天就来说说吧。DEMO的获取方式在文末。2.SpringSecurity方法安全SpringSecurity基于注解的安全认证是通过在相关方法上标注安全注解来实现的。2.1启用全局方法安全我们可以在任何@Configuration实例上使用@EnableGlobalMethodSecurity注解来启用全局方法安全注解功能。这个注解提供了三种不同的机制来实现同一个功能,所以我们单独开一章来讨论。3.@EnableGlobalMethodSecurity注解@Retention(value=java.lang.annotation.RetentionPolicy.RUNTIME)@Target(value={java.lang.annotation.ElementType.TYPE})@Documented@Import({GlobalMethodSecuritySelector.class})@EnableGlobalAuthentication@Configurationpublic@interfaceEnableGlobalMethodSecurity{/***基于表达式的方法访问控制*/booleanprePostEnabled()defaultfalse;/***基于@Secured注解*/booleansecuredEnabled()defaultfalse;/***基于JSR-250注解*/booleanjsr250Enabled()defaultfalse;booleanproxyTargetClass()defaultfalse;intorder()defaultOrdered.LOWEST_PRECEDENCE;}@EnableGlobalMethodSecurity在源码中提供了三个方法:prePostEnabled、securedEnabled和jsr250Enabled。当你启用全局基于注解的方法安全功能时,即使用@EnableGlobalMethodSecurity注解时,我们需要选择使用这三个中的一个或几个。接下来我们分别介绍。4.使用prePostEnabled如果在@EnableGlobalMethodSecurity中将prePostEnabled设置为true,则启用基于表达式的方法安全控制。是否访问由表达式运算结果的布尔值决定(true表示开放,false表示拒绝)。有时您可能需要在打开prePostEnabled的情况下执行复杂的操作。Fortheseinstances,youcanextendGlobalMethodSecurityConfiguration,ensuringthat@EnableGlobalMethodSecurity(prePostEnabled=true)ispresentonthesubclass.例如,如果要提供自定义MethodSecurityExpressionHandler:@EnableGlobalMethodSecurity(prePostEnabled=true)publicclassMethodSecurityConfigextendsGlobalMethodSecurityConfiguration{@OverrideprotectedMethodSecurityExpressionHandlercreateExpressionHandler(){//...createandreturncustomMethodSecurityExpressionHandler...returnexpressionHandler;}}上面的例子属于高级操作,一般没有必要。不管是否继承GlobalMethodSecurityConfiguration,都会启用四个注解。@PreAuthorize和@PostAuthorize侧重于方法调用的控制;而@PreFilter和@PostFilter专注于数据控制。4.1@PreAuthorize在标记的方法被调用之前,使用表达式计算是否可以授权访问。接下来,我将总结以下常用的表达方式。基于SecurityExpressionOperations接口的表达式,也就是我们上篇文章中的javaConfig配置。示例:@PreAuthorize("hasRole('ADMIN')")必须具有ROLE_ADMIN角色。基于UserDetails的表达式,用于对当前用户进行一些额外的限定操作。示例:@PreAuthorize("principal.username.startsWith('Felordcn')")只有用户名以Felordcn开头的用户才能访问。基于SpEL表达式对输入参数进行处理。SpEL表达式请参考官方文档。或关注公众号:Felordcn获取相关资讯。示例:@PreAuthorize("#id.equals(principal.username)")输入参数id必须与当前用户名相同。4.2@PostAuthorize标记的方法调用后,通过表达式计算是否可以授权访问。此注释用于@PreAuthorize。不同之处在于方法先执行。然后判断表情。如果该方法没有返回值,实际上等于开启了权限控制;如果有返回值,则实际结果是用户操作成功但没有收到响应。4.3@PreFilter根据方法入参相关的表达式过滤入参。谨慎使用分页!这个过程发生在接口接收参数之前。输入参数必须是java.util.Collection并且支持remove(Object)参数。如果有多个集合,则需要filterTarget=来指定过滤后的集合。内置的保留名称filterObject用作??对集合元素进行评估和过滤的操作的名称。示例://入参为Collectionidstestdata["Felordcn","felord","jetty"]//过滤掉felordjettyasFelordcn@PreFilter(value="filterObject.startsWith('F')",filterTarget="ids")//如果当前用户持有ROLE_AD角色参数全部满足,否则过滤掉那些不以f开头的//DEMO用户不持有ROLE_AD角色,所以只有felord@PreFilter("hasRole('AD')留在集合中)orfilterObject.startsWith('f')")4.4@PostFilter和@PreFilter的区别在于返回值是根据返回值相关的表达式进行过滤的。谨慎使用分页!这个过程发生在接口返回数据之前。相关测试与@PreFilter类似,见文末提供的DEMO。5、使用securedEnabled如果在@EnableGlobalMethodSecurity中将securedEnabled设置为true,角色注解@Secured被启用。注解功能就简单多了。默认情况下,只能根据角色集(默认以ROLE_为前缀)做出访问控制决策。.这个注解的机制是只要声明的角色集(值)包含当前用户拥有的任何角色就可以访问。也就是说,用户的角色集和@Secured注解的角色集之间必须有一个非空的交集。不支持使用SpEL表达式进行决策。6、使用jsr250Enabled开启JSR-250安全控制注解,属于JavaEE(现为jakarta项目)的安全规范。总共有五个安全注释。如果在@EnableGlobalMethodSecurity中将jsr250Enabled设置为true,则启用以下三个JavaEE安全注解:@DenyAll拒绝所有访问@PermitAll允许所有访问@RolesAllowed用法同5中的@Secured7.总结今天又解释了一个注解基于SpringSecurity的静态配置。与基于javaConfig的方法相比,更加灵活细粒度,基于SpEL表达式可以实现更强大的功能。但是,这两种方法仍然是基于编程的静态方法,具有一定的局限性。更灵活的方式应该是动态处理用户角色和资源的映射关系,这是我们以后要解决的问题。本DEMO可关注微信公众号获取:Felordcn回复ss09。