4.3.1 保护请求

需要确保 /design 和 /orders 的请求仅对经过身份验证的用户可用;应该允许所有用户发出所有其他请求。下面的 configure() 实现就是这样做的:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
        .authorizeRequests()
            .antMatchers("/design", "/orders")
                .hasRole("ROLE_USER")
            .antMatchers(“/, "/**").permitAll();
}

对 authorizeRequests() 的调用返回一个对象(ExpressionInterceptUrlRegistry),可以在该对象上指定 URL 路径和模式以及这些路径的安全需求。在这种情况下,指定两个安全规则:

  • 对于 /design 和 /orders 的请求应该是授予 ROLE_USER 权限的用户的请求。

  • 所有的请求都应该被允许给所有的用户。

这些规则的顺序很重要。首先声明的安全规则优先于较低级别声明的安全规则。如果交换这两个安全规则的顺序,所有请求都将应用 permitAll(),那么关于 /design 和 /orders 请求的规则将不起作用。

hasRole() 和 permitAll() 方法只是声明请求路径安全需求的两个方法。表 4.1 描述了所有可用的方法。

表 4.1 定义被保护路径的配置方法

方法

做了什么

access(String)

如果 SpEL 表达式的值为 true,则允许访问

anonymous()

默认用户允许访问

authenticated()

认证用户允许访问

denyAll()

无条件拒绝所有访问

fullyAuthenticated()

如果用户是完全授权的(不是记住用户),则允许访问

hasAnyAuthority(String...)

如果用户有任意给定的权限,则允许访问

hasAnyRole(String...)

如果用户有任意给定的角色,则允许访问

hasAuthority(String)

如果用户有给定的权限,则允许访问

hasIpAddress(String)

来自给定 IP 地址的请求允许访问

hasRole(String)

如果用户有给定的角色,则允许访问

not()

拒绝任何其他访问方法

permitAll()

无条件允许访问

rememberMe()

允许认证了的同时标记了记住我的用户访问

表 4.1 中的大多数方法为请求处理提供了基本的安全规则,但是它们是自我限制的,只支持那些方法定义的安全规则。或者,可以使用 access() 方法提供 SpEL 表达式来声明更丰富的安全规则。Spring Security 扩展了 SpEL,包括几个特定于安全性的值和函数,如表 4.2 所示。

表 4.2 Spring Security 对 SpEL 的扩展

Security 表达式

意指什么

authentication

用户认证对象

denyAll

通常值为 false

hasAnyRole(list of roles)

如果用户有任何给定的角色,则为 true

hasRole(role)

如果用户有给定的角色,则为 true

hasIpAddress(IP Address)

如果请求来自给定 IP 地址,则为 true

isAnonymous()

如果用户是默认用户,则为 true

isAuthenticated()

如果用户是认证了的,则为 true

isFullyAuthenticated()

如果用户被完全认证了的(不是使用记住我进行认证),则为 true

isRememberMe()

如果用户被标记为记住我后认证了,则为 true

permitAll()

通常值为 true

principal

用户 pricipal 对象

表 4.2 中的大多数安全表达式扩展对应于表 4.1 中的类似方法。实际上,使用 access() 方法以及 hasRole() 和 permitAll 表达式,可以按如下方式重写 configure()。

程序清单 4.9 使用 Spring 表达式定义认证规则
@Override
protected void configure(HttpSecurity http) throws Exception {
    http
        .authorizeRequests()
        .antMatchers("/design", "/orders")
            .access("hasRole('ROLE_USER')")
        .antMatchers(“/, "/**").access("permitAll");
}

乍一看,这似乎没什么大不了的。毕竟,这些表达式只反映了已经对方法调用所做的工作。但是表达式可以灵活得多。例如,假设(出于某种疯狂的原因)只想允许具有 ROLE_USER 权限的用户在周二(例如,在周二)创建新的 Taco;你可以重写表达式如下:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
        .authorizeRequests()
            .antMatchers("/design", "/orders")
                .access("hasRole('ROLE_USER') && " +
                        "T(java.util.Calendar).getInstance().get("+
                        "T(java.util.Calendar).DAY_OF_WEEK) == " +
                        "T(java.util.Calendar).TUESDAY")
            .antMatchers(“/”, "/**").access("permitAll");
}

使用基于 SpEL 的安全约束,这种可能性实际上是无限的。我敢打赌,你已经在构思基于 SpEL 的有趣的安全约束了。

只需使用 access() 和程序清单 4.9 中的 SpEL 表达式,就可以满足 Taco Cloud 应用程序的授权需求。现在,让我们来看看如何定制登录页面来适应 Taco Cloud 应用程序的外观。

最后更新于