daoauthenticationprovider

ie3xauqp  于 2021-10-10  发布在  Java
关注(0)|答案(1)|浏览(270)

我发现了一种令人困惑的行为,可能是有意为之,但我无法确定是否如此。
这个 DaoAuthenticationprovider 当我将基本身份验证与特定oauth2配置一起使用时,不会创建。如果在中没有此特定配置 application.yaml 一切正常。如果包括它,我会得到一个内部异常,导致401。我在下面描述了这两种情况。
我的问题是:如果这是正确的行为,如何在不提供自定义authenticationprovider等的情况下运行默认的基本身份验证。?我自己并没有试图实现这一点,因为我不知道如何轻松实现它,而且,如果可能的话,我宁愿使用默认行为。

基本身份验证在以下情况下不起作用:

curl --location --request GET 'http://localhost:8080/actuator/info' --header 'Authorization: Basic dXNlcjpwYXNzd29yZA=='

答案是

{"timestamp":"2021-05-25T13:25:30.198+00:00","status":401,"error":"Unauthorized","message":"","path":"/actuator/info"}

在spring中,我得到一个providernotfoundexception:

/actuator/info at position 5 of 11 in additional filter chain; firing Filter: 'BasicAuthenticationFilter'
2021-05-25 15:23:32.727 DEBUG 4216 --- [nio-8080-exec-2] o.s.s.w.a.www.BasicAuthenticationFilter  : Basic Authentication Authorization header found for user 'user'
2021-05-25 15:23:32.730 DEBUG 4216 --- [nio-8080-exec-2] o.s.s.w.a.www.BasicAuthenticationFilter  : Authentication request for failed!
org.springframework.security.authentication.ProviderNotFoundException: No AuthenticationProvider found for org.springframework.security.authentication.UsernamePasswordAuthenticationToken
    at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:251) ~[spring-security-core-5.3.4.RELEASE.jar:5.3.4.RELEASE]

调试时我发现 DaoAuthenticationProvider provider = new DaoAuthenticationProvider(); 什么时候不叫 InitializeUserDetailsBeanManagerConfigurer.java 获取配置。实际上,似乎InitializeUserDetailsBeanManagerConfigure并不是真正用于配置的,而是我在这里登陆的 GlobalAuthenticationConfigurerAdapter.java .

使一切顺利

我只需要从中删除以下行 application.yaml :

oauth2:
   resourceserver:
      jwt:
         issuer-uri: https://someissuer
         jwk-set-uri: https://somejwkuri

然后我从同一个 curl 中得到200,这个内部Spring:

/actuator/info at position 5 of 11 in additional filter chain; firing Filter: 'BasicAuthenticationFilter'
2021-05-25 15:51:21.845 DEBUG 16540 --- [nio-8080-exec-1] o.s.s.w.a.www.BasicAuthenticationFilter  : Basic Authentication Authorization header found for user 'user'
2021-05-25 15:51:21.845 DEBUG 16540 --- [nio-8080-exec-1] o.s.s.authentication.ProviderManager     : Authentication attempt using org.springframework.security.authentication.dao.DaoAuthenticationProvider
2021-05-25 15:51:22.036 DEBUG 16540 --- [nio-8080-exec-1] o.s.s.w.a.www.BasicAuthenticationFilter  : Authentication success: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@ed8ad585: Principal: org.springframework.security.core.userdetails.User@36ebcb: Username: user; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_ENDPOINT_ADMIN; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Granted Authorities: ROLE_ENDPOINT_ADMIN

代码

应用程序.yaml
还有其他配置,如flyway、hikari、camunda,但所有这些都是独立的,不会影响我观察到的行为。

spring:
   security:
      oauth2:
         resourceserver:
            jwt:
               issuer-uri: https://someissuer
               jwk-set-uri: https://somejwkuri
      user:
         name: user
         password: password
         roles: ENDPOINT_ADMIN

server:
   port: 8080

management:
   endpoints:
      web:
         exposure:
            include: health,info,metrics,prometheus,loggers
         cors:
            allowed-origins: "*"
            allowed-methods: GET,POST
   security:
      enabled: false

logging:
   level:
      org:
         springframework: DEBUG
   pattern:
      console:%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n

WebSecurity配置适配器扩展类
它是一个内部类,因为我使用了多个过滤器链,但在测试期间排除了其他过滤器链-没有影响

public class SecurityConfig {

    @Order(1)
    @Configuration
    public static class BasicAuthSecurityConfig extends WebSecurityConfigurerAdapter {
        // info is excluded on purpose
        private final String[] ENDPOINTS = { "health", "metrics", "prometheus", /* "info" */ }; 
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.csrf().disable().requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests()
                    .requestMatchers(EndpointRequest.to(ENDPOINTS)).permitAll()
                    .requestMatchers(EndpointRequest.toAnyEndpoint()).hasRole("ENDPOINT_ADMIN").and()
                    .httpBasic();
        }
    }

    // other commented out inner classes for oauth and general handling
}

格雷德尔先生
非常简短的版本,但它应该说明它是如何构建的。

plugins {
    //Spring Boot
    id 'org.springframework.boot' version '2.3.3.RELEASE'
}

dependencies {
    compile 'org.springframework.boot:spring-boot-starter-security'
    compile 'org.springframework.boot:spring-boot-starter-actuator'
    compile 'org.springframework.boot:spring-boot-starter-amqp'
    compile 'org.springframework.boot:spring-boot-starter-data-jpa'
    compile 'org.springframework.boot:spring-boot-starter-data-rest'
    compile 'org.springframework.boot:spring-boot-starter-web'
    compile 'org.springframework.cloud:spring-cloud-starter-kubernetes-config'
    compile 'org.springframework.cloud:spring-cloud-starter-openfeign'
    compile 'org.springframework.security:spring-security-oauth2-resource-server'
    compile 'org.springframework.security:spring-security-oauth2-jose'
    compile 'org.springframework.security:spring-security-config'
}
knpiaxh1

knpiaxh11#

快速外植

在application.yml中,您已经配置了http基本身份验证和oauth2资源服务器。
虽然有一个同时使用这两种属性的应用程序是合理的,但是SpringBoot将无法根据这些属性确定您需要的特定配置。
此外,spring引导自动配置用于直接的场景。对于更复杂的配置(如本配置),最好显式创建所需的bean。

深入解释

下面是当前配置的概述。
自从 spring.security.oauth2.resourceserver.jwt.jwk-set-uri 设置后,spring boot会理解您的应用程序是oauth2资源服务器,并生成 JwtDecoder 豆子(看见 OAuth2ResourceServerAutoConfiguration )
如果删除该属性并仅设置 spring.security.user.name ,然后spring boot生成一个默认值 InMemoryUserDetailsManager 使用您提供的用户信息(看见 UserDetailsServiceAutoConfiguration )
然而,当 JwtDecoder bean存在,spring引导不会创建默认值 InMemoryUserDetailsManager .
作为背景,您可以在spring引导待办事项列表中看到这个问题。
现在,您的应用程序没有 InMemoryUserDetailsManager ,但它仍尝试使用http基本身份验证进行身份验证,因为您已指定 http.httpBasic() . 这就是您看到错误消息的原因。

解决方案

与其在application.yml中指定用户凭据,不如创建一个 UserDetailsService 豆子。不管怎样,你都想这样做,因为 InMemoryUserDetailsManager 主要用于测试目的,不建议用于生产。
我会用 InMemoryUserDetailsManager 在本例中,仅说明等效配置。

@EnableWebSecurity
public class SecurityConfiguration {

    @Order(1)
    @Configuration
    public class HttpBasicAuthSecurityConfig extends WebSecurityConfigurerAdapter {
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                    .antMatcher("/basic/**")
                    .authorizeRequests(authorize -> authorize
                        .anyRequest().authenticated()
                    )
                    .httpBasic(withDefaults());
        }

        // Explicitly create bean, instead of configuring user in application.yml
        @Bean
        public UserDetailsService userDetailsService() {
            UserDetails user = User.withDefaultPasswordEncoder()
                    .username("user")
                    .password("password")
                    .roles("USER")
                    .build();
            return new InMemoryUserDetailsManager(user);
        }
    }

    @Order(2)
    @Configuration
    public class ResourceServerConfig extends WebSecurityConfigurerAdapter {

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                .antMatcher("/oauth2/**")
                    .authorizeRequests(authorize -> authorize
                            .anyRequest().authenticated()
                    )
                .oauth2ResourceServer(oauth2 -> oauth2
                        .jwt(withDefaults())
                );
        }

        // Explicitly create bean, instead of configuring decoder in application.yml
        @Bean
        JwtDecoder jwtDecoder() {
            NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder
                    .withJwkSetUri("https://somejwkuri")
                    .build();
            jwtDecoder
                    .setJwtValidator(JwtValidators.createDefaultWithIssuer("https://someissuer"));
            return jwtDecoder;
        }
    }
}

相关问题