Spring Security 设置 Authentication Provider

1、概览

本文将带你了解如何在 Spring Security 中设置 Authentication Provider,相比于使用简单的 UserDetailsService 的标准方案,这样可以提供额外的灵活性。

2、Authentication Provider

Spring Security 提供了多种执行身份认证的选项。这些选项遵循一个简单的契约;一个 AuthenticationProvider 处理一个身份认证请求,并返回一个带有完整凭证的认证对象。

最常见的标准实现是 DaoAuthenticationProvider,它从一个简单的 UserDetailsService(只读)中获取用户详细信息。这个 Service 只能通过用户名检索完整的用户实体,这在大多数情况下已足够。

更多的自定义场景仍需要访问完整的认证请求才能执行身份验证流程。例如,在对某些外部第三方服务进行身份验证时,身份认证请求中的 usernamepassword 都是必要的。

对于这些更高级的场景,需要定义一个自定义的 Authentication Provider:

@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {

    @Override
    public Authentication authenticate(Authentication authentication) 
      throws AuthenticationException {
 
        String name = authentication.getName();
        String password = authentication.getCredentials().toString();
        
        if (shouldAuthenticateAgainstThirdPartySystem()) {
 
            // 使用凭证并对第三方系统进行身份认证
            return new UsernamePasswordAuthenticationToken(
              name, password, new ArrayList<>());
        } else {
            return null;
        }
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return authentication.equals(UsernamePasswordAuthenticationToken.class);
    }
}

注意,返回的 Authentication 对象上设置的授权是空的。这当然是因为授权是针对特定应用的。

3、注册 Authentication Provider

定义了 Authentication Provider,就需要在 XML 安全配置中指定它:

<http use-expressions="true">
    <intercept-url pattern="/**" access="isAuthenticated()"/>
    <http-basic/>
</http>

<authentication-manager>
    <authentication-provider
      ref="customAuthenticationProvider" />
</authentication-manager>

4、Java 配置

相应的 Java 配置如下:

@Configuration
@EnableWebSecurity
@ComponentScan("com.baeldung.security")
public class SecurityConfig {

    @Autowired
    private CustomAuthenticationProvider authProvider;

    @Bean
    public AuthenticationManager authManager(HttpSecurity http) throws Exception {
        AuthenticationManagerBuilder authenticationManagerBuilder = 
            http.getSharedObject(AuthenticationManagerBuilder.class);
        authenticationManagerBuilder.authenticationProvider(authProvider);
        return authenticationManagerBuilder.build();
    }

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.authorizeRequests()
            .anyRequest()
            .authenticated()
            .and()
            .httpBasic();
        return http.build();
    }

}

5、执行身份认证

无论后端是否有自定义 Authentication Provider,从客户端请求身份认证基本上都是一样的。

使用一个简单的 curl 命令来发送认证请求:

curl --header "Accept:application/json" -i --user user1:user1Pass 
    http://localhost:8080/spring-security-custom/api/foo/1

在本例中,使用 Basic Authentication 确保 REST API 的安全。

服务器的响应(200 OK),符合预期:

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Set-Cookie: JSESSIONID=B8F0EFA81B78DE968088EBB9AFD85A60; Path=/spring-security-custom/; HttpOnly
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Sun, 02 Jun 2013 17:50:40 GMT

6、总结

本文介绍了如何在 Spring Security 中自定义 Authentication Provider。


Ref:https://www.baeldung.com/spring-security-authentication-provider