【问题标题】:Basic Auth does not work with multiple configuration基本身份验证不适用于多个配置
【发布时间】:2018-11-17 08:57:38
【问题描述】:

我正在尝试为已配置一些安全策略的应用程序中的一个特定路径设置基本身份验证。 我正在使用 Spring Boot 2.0

这是我的配置:

@Configuration
@EnableWebSecurity
class SecurityConfig {

    @Configuration
    @Order(1)
    inner class TokenWebSecurityConfig : WebSecurityConfigurerAdapter() {

        override fun configure(http: HttpSecurity) {
            http.antMatcher("/token")
                .authorizeRequests()
                .antMatchers(HttpMethod.POST, "/token").permitAll()
                .anyRequest().denyAll()
                .and()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .csrf().disable()
        }
    }

    @Configuration
    @Order(2)
    inner class SignUpWebSecurityConfig(private val signUpBasicAuthConfig: SignUpBasicAuthConfig) :
        WebSecurityConfigurerAdapter() {

        override fun configure(http: HttpSecurity) {
            http
                .antMatcher("/signup")
                .csrf()
                .disable()
                .authorizeRequests()
                .anyRequest().authenticated()
                .and()
                .httpBasic()
                .and()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
        }

        override fun configure(auth: AuthenticationManagerBuilder) {
            auth.inMemoryAuthentication()
                .withUser(signUpBasicAuthConfig.username)
                .password(signUpBasicAuthConfig.password)
                .roles("USER")
        }
    }

    @Configuration
    @Order(3)
    inner class ApiWebSecurityConfig(private val service: TokenAuthenticationUserDetailsService) :
        WebSecurityConfigurerAdapter() {

        override fun configure(http: HttpSecurity) {
            http
                .antMatcher("/api/**")
                .authorizeRequests()
                .anyRequest().authenticated()
                .and()
                .addFilterBefore(authFilter(), RequestHeaderAuthenticationFilter::class.java)
                .authenticationProvider(preAuthProvider())
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .csrf().disable()
        }

        @Bean
        fun authFilter(): TokenAuthenticationFilter = TokenAuthenticationFilter()

        @Bean
        fun preAuthProvider(): AuthenticationProvider =
            PreAuthenticatedAuthenticationProvider().apply { setPreAuthenticatedUserDetailsService(service) }
    }

    @Configuration
    @Order(4)
    inner class HealthWebSecurityConfig : WebSecurityConfigurerAdapter() {

        override fun configure(http: HttpSecurity) {
            http.authorizeRequests().antMatchers(HttpMethod.GET, "/health").permitAll()
        }
    }

    @Configuration
    class AuthenticationManagerProvider : WebSecurityConfigurerAdapter() {

        @Bean
        override fun authenticationManagerBean(): AuthenticationManager = super.authenticationManagerBean()
    }
}

但是@Order(2) 配置总是失败。日志:

14:23:00.318 [http-nio-8080-exec-1] DEBUG o.s.s.w.u.m.AntPathRequestMatcher - Checking match of request : '/signup'; against '/token'
14:23:00.319 [http-nio-8080-exec-1] DEBUG o.s.s.w.u.m.AntPathRequestMatcher - Checking match of request : '/signup'; against '/signup'
14:23:00.320 [http-nio-8080-exec-1] DEBUG o.s.security.web.FilterChainProxy - /signup at position 1 of 11 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
14:23:00.321 [http-nio-8080-exec-1] DEBUG o.s.security.web.FilterChainProxy - /signup at position 2 of 11 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
14:23:00.322 [http-nio-8080-exec-1] DEBUG o.s.security.web.FilterChainProxy - /signup at position 3 of 11 in additional filter chain; firing Filter: 'HeaderWriterFilter'
14:23:00.324 [http-nio-8080-exec-1] DEBUG o.s.security.web.FilterChainProxy - /signup at position 4 of 11 in additional filter chain; firing Filter: 'LogoutFilter'
14:23:00.324 [http-nio-8080-exec-1] DEBUG o.s.s.w.u.matcher.OrRequestMatcher - Trying to match using Ant [pattern='/logout', GET]
14:23:00.324 [http-nio-8080-exec-1] DEBUG o.s.s.w.u.m.AntPathRequestMatcher - Request 'POST /signup' doesn't match 'GET /logout
14:23:00.324 [http-nio-8080-exec-1] DEBUG o.s.s.w.u.matcher.OrRequestMatcher - Trying to match using Ant [pattern='/logout', POST]
14:23:00.324 [http-nio-8080-exec-1] DEBUG o.s.s.w.u.m.AntPathRequestMatcher - Checking match of request : '/signup'; against '/logout'
14:23:00.324 [http-nio-8080-exec-1] DEBUG o.s.s.w.u.matcher.OrRequestMatcher - Trying to match using Ant [pattern='/logout', PUT]
14:23:00.325 [http-nio-8080-exec-1] DEBUG o.s.s.w.u.m.AntPathRequestMatcher - Request 'POST /signup' doesn't match 'PUT /logout
14:23:00.325 [http-nio-8080-exec-1] DEBUG o.s.s.w.u.matcher.OrRequestMatcher - Trying to match using Ant [pattern='/logout', DELETE]
14:23:00.325 [http-nio-8080-exec-1] DEBUG o.s.s.w.u.m.AntPathRequestMatcher - Request 'POST /signup' doesn't match 'DELETE /logout
14:23:00.325 [http-nio-8080-exec-1] DEBUG o.s.s.w.u.matcher.OrRequestMatcher - No matches found
14:23:00.325 [http-nio-8080-exec-1] DEBUG o.s.security.web.FilterChainProxy - /signup at position 5 of 11 in additional filter chain; firing Filter: 'BasicAuthenticationFilter'
14:23:00.325 [http-nio-8080-exec-1] DEBUG o.s.s.w.a.w.BasicAuthenticationFilter - Basic Authentication Authorization header found for user 'username'
14:23:00.327 [http-nio-8080-exec-1] DEBUG o.s.s.authentication.ProviderManager - Authentication attempt using org.springframework.security.authentication.dao.DaoAuthenticationProvider
14:23:00.473 [http-nio-8080-exec-1] WARN  o.s.s.c.bcrypt.BCryptPasswordEncoder - Encoded password does not look like BCrypt
14:23:00.473 [http-nio-8080-exec-1] DEBUG o.s.s.a.d.DaoAuthenticationProvider - Authentication failed: password does not match stored value
14:23:00.474 [http-nio-8080-exec-1] DEBUG o.s.s.w.a.w.BasicAuthenticationFilter - Authentication request for failed: org.springframework.security.authentication.BadCredentialsException: Bad credentials
14:23:00.474 [http-nio-8080-exec-1] DEBUG o.s.s.w.a.DelegatingAuthenticationEntryPoint - Trying to match using RequestHeaderRequestMatcher [expectedHeaderName=X-Requested-With, expectedHeaderValue=XMLHttpRequest]
14:23:00.474 [http-nio-8080-exec-1] DEBUG o.s.s.w.a.DelegatingAuthenticationEntryPoint - No match found. Using default entry point org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint@44d29834

在我看来,由于某种原因,没有使用内存中的 AuthenticationManager。 有什么想法吗?

【问题讨论】:

  • 这似乎与 PasswordEncodoer 有关。我在你的日志中看到了这个警告:14:23:00.473 [http-nio-8080-exec-1] WARN o.s.s.c.bcrypt.BCryptPasswordEncoder - Encoded password does not look like BCrypt
  • @AngeloImmediate 但在这种情况下不应使用密码编码器。就是这样,我认为没有使用正确的身份验证管理器
  • 我认为您可能缺少SignUpWebSecurityConfig 中的http.addFilterAfter(new CustomFilter(), BasicAuthenticationFilter.class);。见baeldung.com/spring-security-basic-authentication
  • 当我将应用程序迁移到 Spring Boot 2.0 时,我在 inMemoryAuthentication 中收到了关于 BCrypt 的类似警告。密码为“123456”应该是“{noop}123456”.....因此,要测试它是否有效,请尝试将您的 inMemoryAuthentication 配置更改为: auth.inMemoryAuthentication() .withUser(signUpBasicAuthConfig.username) .password ("{noop}" + signUpBasicAuthConfig.password) .roles("USER")

标签: spring spring-boot spring-security


【解决方案1】:

我认为您的问题与拥有多个 WebSecurityConfigurerAdapter 实例有关,并希望它们都被使用,据我所知 Spring 只会使用一个。这已在此处进一步讨论:Using multiple WebSecurityConfigurerAdapter in spring boot

My preferred solution是定义一个特殊的接口

public interface ServiceWebSecurityConfigurer {
    void configure(HttpSecurity http) throws Exception;
}

那么就只有一个ConfigurerAdapter:

public class MyConfigurerAdapter extends WebSecurityConfigurerAdapter {

    @Autowired(required = false)
    List<ServiceWebSecurityConfigurer> securityConfigurers;

    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests(). // whatever

        for (ServiceWebSecurityConfigurer serviceSecConfig: securityConfigurers)
            serviceSecConfig.configure(http);

        http.authorizeRequests(). // whatever
    }
}

【讨论】:

    【解决方案2】:

    我遇到了一个类似的问题,从 Spring 2.0 开始,密码需要有一个前缀来指示它们是如何加密的。例如,bcrypt 密码如下所示:

    {bcrypt}2187jbfsafsd
    

    如果这不能立即起作用,我还进行了一些编辑以使其在我的应用程序中起作用:

    我首先创建了一个 Passwordencoder bean 并将其粘贴到 securityconfig 中:

    @Bean
    public static PasswordEncoder passwordEncoder() {
       return PasswordEncoderFactories.createDelegatingPasswordEncoder();
    }
    

    然后我修改了 DaoAuthenticationProvider(也在 securityconfig 中):

    @Bean
    public DaoAuthenticationProvider authenticationProvider() {
        final DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
        authProvider.setUserDetailsService(userDetailsService);
        authProvider.setPasswordEncoder(passwordEncoder);
        return authProvider;
    }
    

    最后我将编码器自动连接到安全配置中:

    @Autowired
    private PasswordEncoder passwordEncoder;
    

    希望对你有帮助

    【讨论】:

      猜你喜欢
      • 2020-04-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-04-19
      • 2021-11-15
      • 2021-01-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多