带有自定义 AuthenticationManager 的 SpringSecurity BasicAuthenticationFilter

SpringSecurity BasicAuthenticationFilter with custom AuthenticationManager

对于 BasicAuthenticationFilter,我正在尝试注入我自己的 AuthenticationManager。 但是当我调试启动时,我总是发现 Class BasicAuthenticationFilter.java 没有使用我的 AuthenticationManager.

如何将其传递到 BasicAuthenticationFilter 中?

我正在使用 SpringBoot 2.1.0 和 Spring-Security-Oauth2 2.0.1

AuthorizationConfiguration.java

@Configuration
@EnableAuthorizationServer
public class AuthorizationConfiguration extends 
AuthorizationServerConfigurerAdapter {

@Autowired
private AuthenticationManager authenticationManager;

@Autowired
@Qualifier("passwordEncoder")
private PasswordEncoder passwordEncoder;

@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
    System.out.println(passwordEncoder.encode("SECRET"));
    clients
    .inMemory()
    .withClient("clientapp")
    .authorizedGrantTypes("client_credentials")
    .authorities("USER")
    .scopes("read", "write")
    .secret(passwordEncoder.encode("SECRET"));

}

@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
    security.tokenKeyAccess("permitAll()");
}

@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
    endpoints.authenticationManager(authenticationManager);
}
}

WebSecurityConfiguration.java

@Configuration
@EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter{

@Override
@Bean(name = BeanIds.AUTHENTICATION_MANAGER)
@Primary
public AuthenticationManager authenticationManagerBean() throws Exception {
    return super.authenticationManager();
}


@Bean
public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder(16); 
}

@Override
public void configure(WebSecurity web) throws Exception {
    web.ignoring()
    .antMatchers(ResourceConfiguration.TEST_PATHS);
}

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    DaoAuthenticationProvider daoAuth = new DaoAuthenticationProvider();
    daoAuth.setPasswordEncoder(passwordEncoder());
    auth.authenticationProvider(daoAuth);
}

感谢您的帮助。

在您的 WebSecurityConfiguration 中,authenticationManagerBean() 应该 return 您自己的 AuthenticationManager bean 实例,而不是 super.authenticationManager()?

根据您给定的配置,您实际上会得到 BasicAuthenticationFilter 的两个实例。两者都应该让你的 AuthenticationManager 就好了。但是,对于其中一个,它是父 AuthenticationManager,这意味着您还应该在调试器中检查 authenticationManager.parent 属性。

您的 AuthenticationManager 可能存在一些问题。

Spring Security OAuth 将创建两个过滤器链(随后是两个 BasicAuthenticationFilter、两个 AuthenticationManager);一个用于 OAuth 端点,例如 /oauth/token,另一个用于其他一切。

为 OAuth 端点创建的过滤器链采用您通过 ClientDetailsServiceConfigurer 指定的 UserDetailsService 并将其应用于您指定的 AuthenticationManager

如果我把你的配置放到我的 IDE 中,然后执行:

curl --user clientapp:SECRET localhost:8080/oauth/token -dgrant_type=client_credentials

然后它会带着一个令牌回来就好了。

但是,对于其余请求,它不会将这些客户端应用到 AuthenticationManager。这样做的原因是,对于授权服务器,通常有两种不同类型的用户:客户端和最终用户。客户端需要使用 OAuth API 而用户只需要使用 Web 应用程序(登录等)。

这意味着如果您尝试这样做:

curl --user clientapp:SECRET localhost:8080

不行。该组用户尚未应用于该过滤器链。

如果您有非 OAuth2 端点,则需要在 UserDetailsService 中自行指定一组用户。如果没有这个,当您尝试使用 basic 访问这些端点时,没有用户可以查找。

此外,默认 AuthenticationManager 会自动选择您的 PasswordEncoder。因此,除了您的 WebSecurityConfiguration#configure 方法,您还可以这样做:

@Bean
public UserDetailsService userDetailsService() {
    return new InMemoryUserDetailsService(User
        .withUsername("user")
        .password(passwordEncoder().encode("password"))
        .role("USER")
        .build());
}

(如果您需要做一些更复杂的事情,您也可以自定义 AuthenticationManager。)

使用您发布的应用程序尝试此操作(针对上述内容再次更改 WebSecurityConfiguration 中的 configure 方法),我也可以这样做:

curl --user user:password localhost:8080

问题是我在build.gradle

中使用了错误的包

为了解决这个问题,我添加了以下包:

build.gradle

implementation("org.springframework.security.oauth.boot:spring-security-oauth2-autoconfigure:${springBootVersion}")