在本章中我们将会看到如何使用Spring Security保护bean方法。
1.使用注解保护方法
在Spring Security中实现方法级安全性的最常见办法是使用特定的注解,将这些注解应用到需要保护的方法上。这样有几个好处,最重要的是当我们在编辑器中查看给定的方法时,能够很清楚地看到它的安全规则。
Spring Security提供了三种不同的安全注解:
- Spring Security自带的@Security注解
- JSR-250的@RolesAllowed注解
- 表达式驱动的注解,包括@PreAuthorize,@PostAuthorize,@PreFilter,@PostFilter。
1.1使用@Secured注解限制方法调用
在Spring中,如果要启用基于注解的方法安全性,关键之处在于要在配置类上使用@EnableGlobalMethodSecurity:
- 1
- 2
- 3
- 4
- 5
GlobalMethodSecurityConfiguration类能够为方法级别的安全性提供更精细的配置。
如果securedEnabled属性的值为true的话,将会创建一个切点,这样的话Spring Security切面就会包装带有@Security注解的方法。(所以最好把要控制权限的方法放在service层)。
示例:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
@Secured注解的不足之处在于它是spring特定的注解。如果更倾向于使用Java标准定义的注解,那么你应该考虑使用@RolesAllowed注解
1.2在Spring Security中使用JSR-250的@RolesAllowed注解
@RolesAllowed是JSR-250定义的Java标准注解。如果选择@RolesAllowed的话,需要将@EnableGlobalMethodSecurity的jsr250Enabled属性设置为true,以开启此功能:
- 1
- 2
- 3
- 4
- 5
使用示例:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
2.使用表达式实现方法级别的安全性
Spring Security 3.0提供了4个新的注解,可以使用SpEL表达式来保护方法调用
注解 | 描述 |
---|---|
@PreAuthorize | 在方法调用之前,基于表达式的计算结果来限制对方法的访问 |
@PostAuthorize | 允许方法调用,但是如果表达式计算结果为false,将抛出一个安全性异常 |
@PostFilter | 允许方法调用,但必须按照表达式来过滤方法的结果 |
@PreFilter | 允许方法调用,但必须在进入方法之前过滤输入值 |
首先,我们需要将@EnableGlobalMethodSecurity的prePostEnabled属性值设为true,从而开启它们:
- 1
- 2
- 3
- 4
- 5
2.1表述方法访问规则
@PreAuthorize和@PostAuthorize能够基于表达式的计算结果来限制方法的访问。区别在于表达式执行的时机。@PreAuthorize的表达式会在方法调用之前执行,如果表达式的计算结果不为true的话,将会阻止方法执行。与之相反,@PostAuthorize的表达式知道方法返回才会执行,然后根据结果决定是否抛出安全性异常,如果为false,会抛出一个AccessDeniedException异常,而调用者也得不到返回的值。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
为了便利地访问受保护方法的返回对象,Spring Security在SpEL中提供了名为returnObject的变量。
2.2 过滤方法的输入和输出
@PostFilter和@PreFilter都使用一个SpEL作为值参数,但是这个表达式不是用来限制方法访问的,@PostFilter会使用这个表达式计算该方法所返回集合的每个成员,将计算结果为false的成员从结果集中除掉,返回结果集。而@PreFilter过滤的是要进入方法中的集合,同样会对每一条数据进行检查,只有满足表达式(即表达式返回true)的结果才能保留在集中,最终传到方法里面。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
filterObject对象引用的是传入或传出的List中的某一个元素。