Spring Security基于表达式的访问控制

概述

相比较以前使用配置属性(configuration attributes)或access-decision voters,Spring Security 3.0提供了基于EL表达式的访问控制(authorization mechanism)。该表达式可以用于web和method访问控制(access control)。

Security提供的EL表达式root object是SecurityExpressionRoot,注意使用时,如果是role的参数,则不需要加上“ROLE_”前缀,系统会自动加上,如果需要修改该前缀,请使用DefaultWebSecurityExpressionHandler.

在SecurityExpressionRoot的子类WebSecurityExpressionRoot可以使用request访问HttpServletRequest。

常见用法

针对URL访问控制

<http>
    <intercept‐url pattern="/admin*" access="hasRole('admin') and hasIpAddress('192.168.1.0/24')"/>
http>

除了使用SecurityExpressionRoot内部定义的方法,也可以自己定义,比如:

public class WebSecurity {
    public boolean check(Authentication authentication, HttpServletRequest request)     {
        ...
    }
}
<http>
    <intercept‐url pattern="/user/{userId}/**" access="@webSecurity.checkUserId(authentication,#userId)"/>
http>

或者

http.authorizeRequests().antMatchers("/user/{userId}/**").access("@@webSecurity.checkUserId(authentication,#userId)")

针对Method访问控制

针对方法级别的访问控制比较复杂,Spring Security提供了四种注解,分别是@PreAuthorize , @PreFilter , @PostAuthorize 和 @PostFilter,如果需要使用该注解,还需要进行配置,如下:

<globalmethodsecurity prepostannotations="enabled"/>
  • @PreAuthorize

    用于判断用户是否有权限使用,如下所示,只有“ROLE_USER”的用户才有权限调用。

    @PreAuthorize("hasRole('USER')")
    public void create(Contact contact);

    如果EL表达式需要使用method的入参,则可以使用#标注(其他请查看DefaultSecurityParameterNameDiscoverer),例如:

    @PreAuthorize("hasPermission(#contact, 'admin')")
    public void deletePermission(Contact contact, Sid recipient, Permission permission);

    在JDK8以前,接口的参数名称会丢失,此时采用上面的方法将会无法工作,这是需要使用@P注解或@Param(使用AnnotationParameterNameDiscoverer),例如:

    @PreAuthorize("#c.name == authentication.name")
    public void doSomething(@P("c") Contact contact);
    
    @PreAuthorize("#n == authentication.name")
    Contact findContactByName(@Param("n") String name);

    在JDK8,可以使用-parameters参数,以使得编译时带上source,获取接口参数名称。而 Spring 4+ 支持这种。

  • @PostAuthorize

    用于在方法调用后执行授权,可在表达式中使用 returnObject获取返回值。

  • @PreFilter和@PostFilter

    两者用于过滤collections and arrays,对满足条件的item进行删除,可以使用filterObject访问输入输出对象。Spring Security会遍历这个容器,并对每一个item执行el表达式,如果结果为false,则删除。对于输入参数,如果有多个collection,需要通过属性filterTarget指定。

    注意对数据量特别大的参数,不建议使用,因为效率不高。为了简化访问控制写法,可以自定义annotation,例如:

    @Retention(RetentionPolicy.RUNTIME)
    @PreAuthorize("#contact.name == authentication.name")
    public @interface ContactPermission {}

你可能感兴趣的:(专案系列,教程系列)