朋友们都知道宋哥最近在做天津项目。项目中涉及到一个问题,就是数据权限过滤。很多朋友对这个问题特别着迷。希望松哥松哥能完成一篇文章说说,嗯,安排一下。在讲数据权限之前,我们有必要给大家介绍一下SpringSecurity中的权限注解。搞定后,再去TienChin项目的权限注解,你会发现很容易。一、SpringSecurity中的权限注解SpringSecurity支持多种权限注解。首先,我们需要通过@EnableGlobalMethodSecurity注解开启权限注解的使用,如下:@Configuration@EnableGlobalMethodSecurity(prePostEnabled=true,securedEnabled=true,jsr250Enabled=true)publicclassSecurityConfigextendsWebSecurityConfigurerAdapter{}在这个注解中,我们设置一共有三个属性:prePostEnabled:表示开启SpringSecurity提供的四个权限注解,@PostAuthorize、@PostFilter、@PreAuthorize和@PreFilter,这四个注解支持Permission表达式,支持SpEL,功能丰富。securedEnabled:开启SpringSecurity提供的@Secured注解,不支持权限表达式。jsr250Enabled:启用JSR-250提供的注解,主要包括@DenyAll、@PermitAll和@RolesAllowed。这些注释不支持权限表达式。上述注解的含义如下:@PostAuthorize:在目标方法执行后进行权限验证。@PostFilter:过滤目标方法执行后方法的返回结果。@PreAuthorize:在目标方法执行之前进行权限验证。@PreFilter:在目标方法执行之前过滤方法参数。@Secured:访问目标方法必须有对应的角色。@DenyAll:拒绝所有访问。@PermitAll:允许所有访问。@RolesAllowed:访问目标方法必须有对应的角色。这就是全部,当然,一般来说,我们只需要设置prePostEnabled=true即可,也就是前四个注解基本可以满足大部分需求。此外,还有一种“老”的方法来配置基于方法的权限管理,就是通过XML文件来配置方法拦截规则。目前很少使用XML文件来配置SpringSecurity,所以这个方法我们就不做过多介绍了。介绍。感兴趣的小伙伴可以查看官网的相关介绍:https://docs.spring.io/spring-security/site/docs/5.4.0/reference/html5/#secure-object-impls。2.权限注解实践下面我们通过几个简单的案例来学习一下以上不同注解的用法。首先创建一个SpringBoot项目,引入Web和SpringSecurity依赖。项目创建完成后,添加如下配置文件:@EnableGlobalMethodSecurity(prePostEnabled=true,securedEnabled=true,jsr250Enabled=true)publicclassSecurityConfig{}为了方便,我们将使用单元测试进行验证,所以这里不需要额外配置,只需通过@EnableGlobalMethodSecurity注解启用其他权限注解即可。接下来创建一个User类供后续使用:publicclassUser{privateIntegerid;私有字符串用户名;//省略getter/setter}准备工作完成后,我们来一一解释前面注解的用法。2.1@PreAuthorize@PreAuthorize注解可以在目标方法执行前对其进行安全验证。安全验证时,可以直接使用权限表达式。例如,可以定义如下方法:@ServicepublicclassHelloService{@PreAuthorize("hasRole('ADMIN')")publicStringhello(){return"hello";}}这里使用了权限表达式hasRole,表示执行该方法必须有ADMIN角色才能访问,否则无法访问。接下来,我们在单元测试中测试这个方法:@SpringBootTestclassBasedOnMethodApplicationTests{@AutowiredHelloServicehelloService;@Test@WithMockUser(roles="ADMIN")voidpreauthorizeTest01(){Stringhello=helloService.hello();assertNotNull(你好);assertEquals("你好",你好);}}通过@WithMockUser(roles="ADMIN")注解设置当前执行的用户角色为ADMIN,然后调用helloService中的方法进行测试。如果将用户角色设置为其他角色,单元测试将不会通过。当然这里除了hasRole表达式,还可以使用其他的权限表达式,甚至可以同时使用多个权限表达式,如下所示:@ServicepublicclassHelloService{@PreAuthorize("hasRole('ADMIN')和身份验证.name=='javaboy'")publicStringhello(){return"hello";}}表示访问者的名字必须是javaboy,并且需要有ADMIN角色才能访问这个方法。此时,使用如下代码进行测试:@SpringBootTestclassBasedOnMethodApplicationTests{@AutowiredHelloServicehelloService;@Test@WithMockUser(roles="ADMIN",username="javaboy")voidpreauthorizeTest01(){Stringhello=helloService.hello();assertNotNull(你好);assertEquals("你好",你好);}}在@PreAuthorize注解中,还可以使用#来引用方法的参数,并进行验证。例如下面的方法表示请求者的用户名必须等于方法参数名的值,方法才能执行:@PreAuthorize("authentication.name==#name")publicStringhello(Stringname){return"hello:"+name;}测试方法如下:@Test@WithMockUser(username="javaboy")voidpreauthorizeTest02(){Stringhello=helloService.hello("javaboy");assertNotNull(你好);assertEquals("hello:javaboy",hello);}当模拟的用户名和方法参数相等时,单元测试通过。2.2@PreFilter@PreFilter主要是对方法的请求参数进行过滤,其中包含一个内置对象filterObject来表示要过滤的参数。如果该方法只有一个参数,则内置的filterObject对象代表该参数;如果该方法有多个参数,则需要使用filterTarget指定filterObject代表哪个对象:@PreFilter(value="filterObject.id%2!=0",filterTarget="users")publicvoidaddUsers(List
