Spring Security 配置不同 URL 的认证和授权规则

1、概览

本文将带你了解如何在 Spring Security 中针对不同的 URL 进行不同的安全配置。

2、设置

创建应用,在 pom.xml 中添加 WebSecurity 依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency> 
    <groupId>org.springframework.boot</groupId> 
    <artifactId>spring-boot-starter-security</artifactId> 
</dependency> 

3、创建 API

创建一个包含两个 API 的 RESTful 服务:Product(产品) API 和 Customer(客户) API。

3.1、Product API

创建 ProductController。它包含一个 getProducts 方法,该方法返回产品列表:

@RestController("/products")
public class ProductController {
    
    @GetMapping
    public List<Product> getProducts() {
        return new ArrayList<>(Arrays.asList(
          new Product("Product 1", "Description 1", 1.0),
          new Product("Product 2", "Description 2", 2.0)
        ));
    }
}

3.2、Customer API

同样,定义 CustomerController

@RestController("/customers")
public class CustomerController {
    
    @GetMapping("/{id}")
    public Customer getCustomerById(@PathVariable("id") String id) {
        return new Customer("Customer 1", "Address 1", "Phone 1");
    }
}

在一个典型的 Web 应用中,所有用户(包括访客用户)都可以获取产品列表。

不过,只有管理员才可以通过 ID 获取客户详细信息。因此,在定义安全配置时要考虑到这一点。

4、设置安全配置

创建 SecurityConfiguration

@Configuration
public class SecurityConfiguration {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.authorizeRequests()
            .antMatchers("/products/**")
            .permitAll()
            .and()
            .authorizeRequests()
            .antMatchers("/customers/**")
            .hasRole("ADMIN")
            .anyRequest()
            .authenticated()
            .and()
            .httpBasic();
        return http.build();
    }
}

如上,创建了一个 SecurityFilterChain Bean 来配置应用的安全设置。

此外,还需要为应用配置用户,用于 Basic Authentication(认证)。

4.1、允许请求 Product API

  • authorizeRequests():该方法告诉 Spring 在授权请求时使用以下规则。
  • antMatchers("/products/**"):这指定了安全配置适用的 URL 模式。将其与 permitAll() 操作进行了链接。如果请求路径中包含 /products,则允许请求进入 Controller。
  • 可以使用 and() 方法在配置中添加更多规则。

这标志着一连串规则的结束。后面的其他规则也将应用于请求。因此,需要确保规则不会相互冲突。一个好的做法是在顶部定义通用规则,在底部定义更具体的规则。

4.2、仅允许 Admin 访问 Customer API

现在来看看配置的第二部分:

  • 使用 authorizeRequests() 方法开启新的规则。
  • antMatchers("/customers/**").hasRole("ADMIN"):如果 URL 路径中包含 /customers,就会检查请求用户是否具有 ADMIN 角色。

如果用户未通过身份认证,将导致 “401 Unauthorized” 错误。如果用户没有正确的角色,则会导致 “403 Forbidden” 错误。

4.3、默认规则

现在已经添加了匹配某些请求的匹配项。现在,为其他请求定义一些默认行为。

anyRequest().authenticated() - anyRequest() 为任何不符合前面规则的请求定义了一个规则链。在本例中,只要这些请求通过了身份认证,就会被通过。

注意,配置中只能有一条默认规则,而且必须放在最后。如果试图在添加默认规则后再添加规则,就会出现异常 - “Can’t configure antMatchers after anyRequest”。

5、测试

使用 cURL 测试这两个 API。

5.1、测试 Product API

$ curl -i http://localhost:8080/products
[
  {
    "name": "Product 1",
    "description": "Description 1",
    "price": 1.0
  },
  {
    "name": "Product 2",
    "description": "Description 2",
    "price": 2.0
  }
]

响应和预想的一样。

5.2、测试 Customer API

$ curl -i http://localhost:8080/customers/1

响应体为空。

查看响应 Header,就会看到 “401 Unauthorized” 状态码。这是因为只有通过身份认证的 ADMIN 用户才能访问 Customer API。

现在,在请求中添加认证信息后再试一次:

$ curl -u admin:password -i http://localhost:8080/customers/1 
{
  "name": "Customer 1",
  "address": "Address 1",
  "phone": "Phone 1"
}

成功地访问了 Customer API。

6、总结

本文介绍了如何在 Spring Boot 应用中设置 Spring Security,以及如何使用 antMatchers() 方法为不同的 URL 设置不同的认证、授权规则。


参考:https://www.baeldung.com/spring-security-configuring-urls