Spring Authorization Server предоставляет “Не найдено AuthenticationProvider”

Вопрос или проблема

Я пытаюсь настроить сервер авторизации с использованием spring-boot-starter-oauth2-authorization-server. Проблема в том, что когда я пытаюсь ввести свой логин и пароль, возникает ошибка “Не найден AuthenticationProvider”. Пожалуйста, помогите мне это исправить.

Класс SecurityConfig

@EnableWebSecurity
@Configuration(proxyBeanMethods = false)
public class SecurityConfig {

    @Bean
    public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests(authorize ->
                authorize.anyRequest().authenticated())
                .csrf(AbstractHttpConfigurer::disable);
        return http.formLogin(Customizer.withDefaults()).build();
    }

    public UserDetailsService userDetailsService() {
        UserDetails user = User.builder()
                .username("admin")
                .password("{noop}password")
                .roles("USER")
                .build();
        return new InMemoryUserDetailsManager(user);
    }

}

Класс AuthorizationServerConfig

@Configuration
@RequiredArgsConstructor
public class AuthorizationServerConfig {

    private final OAuth2AuthorizationServerProperties authorizationServerProperties;

    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public SecurityFilterChain authServerSecurityFilterChain(HttpSecurity http) throws Exception {
        OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
        http.exceptionHandling(exception ->
                exception.authenticationEntryPoint(
                        new LoginUrlAuthenticationEntryPoint("/login")));
        return http.build();
    }

    public RegisteredClientRepository registeredClientRepository() {
        return new InMemoryRegisteredClientRepository(
                RegisteredClient.withId("test-client-id")
                        .clientName("Test Client")
                        .clientId("test-client")
                        .clientSecret("{noop}test-client")
                        .redirectUri("http://localhost:5000/code")
                        .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
                        .authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
                        .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
                        .authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
                        .build()
        );
    }

    @Bean
    public JWKSource<SecurityContext> jwkSource() {
        KeyPair keyPair = generateRsaKey();
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
        RSAKey rsaKey = new RSAKey.Builder(publicKey)
                .privateKey(privateKey)
                .keyID(UUID.randomUUID().toString())
                .build();
        JWKSet jwkSet = new JWKSet(rsaKey);
        return ((jwkSelector, securityContext) -> jwkSelector.select(jwkSet));
    }

    private static KeyPair generateRsaKey() {
        KeyPair keyPair;
        try {
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
            keyPairGenerator.initialize(2048);
            keyPair = keyPairGenerator.generateKeyPair();
        } catch (Exception ex) {
            throw new IllegalStateException(ex);
        }
        return keyPair;
    }

    @Bean
    public JwtDecoder jwtDecoder(JWKSource<SecurityContext> jwkSource) {
        return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource);
    }

    @Bean
    public AuthorizationServerSettings authorizationServerSettings() {
        return AuthorizationServerSettings.builder()
                .issuer(authorizationServerProperties.getIssuer())
                .build();
    }

}

application.yaml

server:
  port: 7777

logging:
  level:
    root: DEBUG
    org.apache.tomcat.util.net.NioEndpoint: ERROR
    sun.rmi: ERROR
    java.io: ERROR
    javax.management: ERROR

spring:
  application:
    name: j-sso
  security:
    oauth2:
      authorizationserver:
        issuer-url: http://localhost:7777

логи трассировки

2024-11-13T01:03:51.717+03:00 TRACE 3596 --- [j-sso] [nio-7777-exec-6] o.s.s.w.s.HttpSessionRequestCache        : Запрос не был сохранен, так как он не соответствует [And [Ant [pattern='/**', GET], Not [Ant [pattern='/**/favicon.*']], Not [MediaTypeRequestMatcher [contentNegotiationStrategy=org.springframework.web.accept.ContentNegotiationManager@1858a268, matchingMediaTypes=[application/json], useEquals=false, ignoredMediaTypes=[*/*]]], Not [RequestHeaderRequestMatcher [expectedHeaderName=X-Requested-With, expectedHeaderValue=XMLHttpRequest]], Not [MediaTypeRequestMatcher [contentNegotiationStrategy=org.springframework.web.accept.ContentNegotiationManager@1858a268, matchingMediaTypes=[multipart/form-data], useEquals=false, ignoredMediaTypes=[*/*]]], Not [MediaTypeRequestMatcher [contentNegotiationStrategy=org.springframework.web.accept.ContentNegotiationManager@1858a268, matchingMediaTypes=[text/event-stream], useEquals=false, ignoredMediaTypes=[*/*]]]]]
2024-11-13T01:03:51.717+03:00 DEBUG 3596 --- [j-sso] [nio-7777-exec-6] s.w.a.DelegatingAuthenticationEntryPoint : Пытаемся выполнить сопоставление, используя And [Not [RequestHeaderRequestMatcher [expectedHeaderName=X-Requested-With, expectedHeaderValue=XMLHttpRequest]], MediaTypeRequestMatcher [contentNegotiationStrategy=org.springframework.web.accept.ContentNegotiationManager@1858a268, matchingMediaTypes=[application/xhtml+xml, image/*, text/html, text/plain], useEquals=false, ignoredMediaTypes=[*/*]]]
2024-11-13T01:03:51.718+03:00 DEBUG 3596 --- [j-sso] [nio-7777-exec-6] s.w.a.DelegatingAuthenticationEntryPoint : Совпадение найдено! Выполнение org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint@2fd72332
2024-11-13T01:03:51.718+03:00 DEBUG 3596 --- [j-sso] [nio-7777-exec-6] o.s.s.web.DefaultRedirectStrategy        : Перенаправление на http://localhost:7777/login
2024-11-13T01:03:51.718+03:00 TRACE 3596 --- [j-sso] [nio-7777-exec-6] o.s.s.w.header.writers.HstsHeaderWriter  : Заголовок HSTS не вставляется, так как он не соответствует запросу [Является безопасным]
2024-11-13T01:03:51.732+03:00 TRACE 3596 --- [j-sso] [nio-7777-exec-7] o.s.security.web.FilterChainProxy        : Пытаемся сопоставить запрос с DefaultSecurityFilterChain [RequestMatcher=any request, Filters=[org.springframework.security.web.session.DisableEncodeUrlFilter@9fdc290, org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@1fc0cdb4, org.springframework.security.web.context.SecurityContextHolderFilter@7793ad58, org.springframework.security.web.header.HeaderWriterFilter@62765aec, org.springframework.security.web.csrf.CsrfFilter@5dfe23e8, org.springframework.security.web.authentication.logout.LogoutFilter@5af64ce0, org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter@49f3ff41, org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter@4207852d, org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter@733e2d75, org.springframework.security.web.authentication.www.BasicAuthenticationFilter@4f2d014a, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@16132f21, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@4640195a, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@2a4db2b5, org.springframework.security.web.access.ExceptionTranslationFilter@50b0afd7, org.springframework.security.web.access.intercept.AuthorizationFilter@56846330]] (1/1)
2024-11-13T01:03:51.733+03:00 DEBUG 3596 --- [j-sso] [nio-7777-exec-7] o.s.security.web.FilterChainProxy        : Защита GET /login
2024-11-13T01:03:51.733+03:00 TRACE 3596 --- [j-sso] [nio-7777-exec-7] o.s.security.web.FilterChainProxy        : Вызов DisableEncodeUrlFilter (1/15)
2024-11-13T01:03:51.733+03:00 TRACE 3596 --- [j-sso] [nio-7777-exec-7] o.s.security.web.FilterChainProxy        : Вызов WebAsyncManagerIntegrationFilter (2/15)
2024-11-13T01:03:51.733+03:00 TRACE 3596 --- [j-sso] [nio-7777-exec-7] o.s.security.web.FilterChainProxy        : Вызов SecurityContextHolderFilter (3/15)
2024-11-13T01:03:51.733+03:00 TRACE 3596 --- [j-sso] [nio-7777-exec-7] o.s.security.web.FilterChainProxy        : Вызов HeaderWriterFilter (4/15)
2024-11-13T01:03:51.733+03:00 TRACE 3596 --- [j-sso] [nio-7777-exec-7] o.s.security.web.FilterChainProxy        : Вызов CsrfFilter (5/15)
2024-11-13T01:03:51.733+03:00 TRACE 3596 --- [j-sso] [nio-7777-exec-7] o.s.security.web.csrf.CsrfFilter         : Защита от CSRF не была осуществлена, так как запрос не соответствовал CsrfNotRequired [TRACE, HEAD, GET, OPTIONS]
2024-11-13T01:03:51.733+03:00 TRACE 3596 --- [j-sso] [nio-7777-exec-7] o.s.security.web.FilterChainProxy        : Вызов LogoutFilter (6/15)
2024-11-13T01:03:51.733+03:00 TRACE 3596 --- [j-sso] [nio-7777-exec-7] o.s.s.w.a.logout.LogoutFilter            : Запрос не соответствует Ant [pattern='/logout', POST]
2024-11-13T01:03:51.733+03:00 TRACE 3596 --- [j-sso] [nio-7777-exec-7] o.s.security.web.FilterChainProxy        : Вызов UsernamePasswordAuthenticationFilter (7/15)
2024-11-13T01:03:51.733+03:00 TRACE 3596 --- [j-sso] [nio-7777-exec-7] w.a.UsernamePasswordAuthenticationFilter : Запрос не соответствует Ant [pattern='/login', POST]
2024-11-13T01:03:51.734+03:00 TRACE 3596 --- [j-sso] [nio-7777-exec-7] o.s.security.web.FilterChainProxy        : Вызов DefaultLoginPageGeneratingFilter (8/15)
2024-11-13T01:03:51.734+03:00 TRACE 3596 --- [j-sso] [nio-7777-exec-7] o.s.s.w.header.writers.HstsHeaderWriter  : Заголовок HSTS не вставляется, так как он не соответствует запросу [Является безопасным]

Ошибка
вставьте описание изображения здесь

Я пытался настроить по примеру https://wankhedeshubham.medium.com/spring-boot-security-with-userdetailsservice-and-custom-authentication-provider-3df3a188993f, но это мне не помогло.

Ответ или решение

Решение проблемы "No AuthenticationProvider found" в Spring Authorization Server

При настройке Spring Authorization Server могут возникнуть различные ошибки, одной из которых является ошибка "No AuthenticationProvider found". Эта проблема обычно связана с конфигурацией аутентификации и управления пользователями. В этом ответе мы рассмотрим основные шаги, чтобы помочь вам решить эту проблему, основываясь на предоставленной вами информации.

Анализ кода и конфигурации

Ваш код состоит из двух основных классов конфигурации: SecurityConfig и AuthorizationServerConfig. Давайте рассмотрим каждый из них и поймем, где могут быть проблемы:

1. Класс SecurityConfig

@EnableWebSecurity
@Configuration(proxyBeanMethods = false)
public class SecurityConfig {

    @Bean
    public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests(authorize ->
                authorize.anyRequest().authenticated())
                .csrf(AbstractHttpConfigurer::disable);
        return http.formLogin(Customizer.withDefaults()).build();
    }

    public UserDetailsService userDetailsService() {
        UserDetails user = User.builder()
                .username("admin")
                .password("{noop}password")
                .roles("USER")
                .build();
        return new InMemoryUserDetailsManager(user);
    }
}

В этом месте вы создали UserDetailsService, который предоставляет административного пользователя в памяти. Однако в вашем фильтре безопасности отсутствует явная связь между UserDetailsService и AuthenticationProvider, что приводит к ошибке "No AuthenticationProvider found".

2. Класс AuthorizationServerConfig

@Configuration
@RequiredArgsConstructor
public class AuthorizationServerConfig {

    private final OAuth2AuthorizationServerProperties authorizationServerProperties;

    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public SecurityFilterChain authServerSecurityFilterChain(HttpSecurity http) throws Exception {
        OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
        http.exceptionHandling(exception ->
                exception.authenticationEntryPoint(
                        new LoginUrlAuthenticationEntryPoint("/login")));
        return http.build();
    }

    // Другие методы конфигурации
}

Здесь вы настраиваете сервер авторизации, но не указываете UserDetailsService для обработки аутентификации. Это означает, что аутентификация будет искать подходящий AuthenticationProvider, но не сможет его найти, так как он не был явно определён.

Решение проблемы

Для решения вашей проблемы следует внести несколько изменений в класс SecurityConfig. Вам необходимо зарегистрировать UserDetailsService как бини, а также явно определить AuthenticationProvider, чтобы обеспечить правильное взаимодействие между вашими конфигурациями. Добавьте метод для создания AuthenticationProvider, который будет использовать ваш UserDetailsService:

@Bean
public AuthenticationProvider authenticationProvider() {
    DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
    provider.setUserDetailsService(userDetailsService());
    provider.setPasswordEncoder(passwordEncoder()); // Не забудьте добавить кодировщик паролей
    return provider;
}

@Bean
public PasswordEncoder passwordEncoder() {
    return new NoOpPasswordEncoder(); // Используйте стартовый (noop) для простоты
}

Затем измените вашу конфигурацию SecurityFilterChain в классе SecurityConfig, чтобы добавить указание на использование этого AuthenticationProvider:

@Bean
public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
    http.authorizeHttpRequests(authorize ->
            authorize.anyRequest().authenticated())
            .and()
            .authenticationProvider(authenticationProvider()) // Добавьте это
            .csrf(AbstractHttpConfigurer::disable);
    return http.formLogin(Customizer.withDefaults()).build();
}

Проверьте ваше приложение

После внесения изменений в конфигурацию, перезапустите ваше приложение и попробуйте снова выполнить вход. Убедитесь, что вы видите корректные журналы и что аутентификация происходит без ошибок.

Заключение

Ошибка "No AuthenticationProvider found" часто возникает из-за недостаточной интеграции различных компонентов аутентификации в Spring Security. Убедившись, что ваши классы конфигурации правильно связаны друг с другом, вы сможете устранить эту ошибку и успешно настроить свой сервер авторизации. Если у вас есть дополнительные вопросы или проблемы, не стесняйтесь обратиться за помощью.

Оцените материал
Добавить комментарий

Капча загружается...