Spring Security getAuthenticationManager () возвращает null в настраиваемом фильтре

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

Я думал, что у меня все на месте, но отправка запроса на проверку того, что я реализовал, приводит к исключению NullPointerException, которое можно отследить до this.getAuthenticationManager () возвращает ноль в моем настраиваемом фильтре. Но я не понимаю почему. К сожалению, очень похожий существующий вопрос мне не помог. Так что я был бы благодарен за помощь; я думаю, вот самые актуальные классы, не стесняйтесь спрашивать, нужны ли еще какие-нибудь.

MyAuthenticationFilter (на основе исходного кода UsernamePasswordAuthenticationFilter) ошибка возникает в последней строке этого:

public class MyAuthenticationFilter extends AbstractAuthenticationProcessingFilter {

    public MyAuthenticationFilter() {
        super(new AntPathRequestMatcher("/login", "POST"));
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
            if (!request.getMethod().equals("POST")) {
                throw new AuthenticationServiceException(
                        "Authentication method not supported: " + request.getMethod());
            }

            String username = request.getParameter("username");
            String password = request.getParameter("password");
            String secondSecret = request.getParameter("secondSecret");

            if (username == null) {
                username = "";
            }

            if (password == null) {
                password = "";
            }

            username = username.trim();

            MyAuthenticationToken authRequest = new MyAuthenticationToken(username, new MyCredentials(password, secondSecret));

            return this.getAuthenticationManager().authenticate(authRequest);
    }
}

Мой конфиг-класс:

@Configuration
@EnableWebSecurity
@EnableWebMvc
@ComponentScan
public class AppConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    MyAuthenticationProvider myAuthenticationProvider;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(myAuthenticationProvider);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.addFilterBefore(new MyAuthenticationFilter(), BasicAuthenticationFilter.class)
                .authorizeRequests().antMatchers("/**")
                    .hasAnyRole()
                    .anyRequest()
                    .authenticated()
                    .and()
                .csrf().disable();
    }

    @Bean
    public ViewResolver viewResolver() {
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        viewResolver.setPrefix("/WEB-INF/views/");
        viewResolver.setSuffix(".jsp");
        return viewResolver;
    }
}

MyAuthenticationProvider:

@Component
public class MyAuthenticationProvider implements AuthenticationProvider {
    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        MyAuthenticationToken myAuthenticationToken = (MyAuthenticationToken) authentication;
        MyCredentials credentials = (MyCredentials) myAuthenticationToken.getCredentials();
        if (credentials.getPassword().equals("sesamOeffneDich") && credentials.getSecondSecret().equals(MyAuthenticationToken.SECOND_SECRET)) {
            myAuthenticationToken.setAuthenticated(true);
            return myAuthenticationToken;
        } else {
            throw new BadCredentialsException("Bad credentials supplied!");
        }
    }

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

Что если добавить в свой конструктор setAuthenticationManager(new NoOpAuthenticationManager());?

StanislavL 23.08.2018 16:31

Я думаю, что OP хочет, чтобы его authenticate удостоился чести.

shinjw 24.08.2018 11:16

Добавил ответ, надеюсь он не слишком плотный

shinjw 24.08.2018 11:16
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
7
3
4 904
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вы должны установить диспетчер аутентификации для своего фильтра. Вы можете сделать это, добавив этот метод в свой класс конфигурации

 @Bean 
    public MyAuthenticationFilter myAuthenticationFilter() {
        MyAuthenticationFilter res = new MyAuthenticationFilter();
        try {
            res.setAuthenticationManager(authenticationManagerBean());
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return res;
    }

и изменив метод настройки с помощью

http.addFilterBefore(myAuthenticationFilter(), BasicAuthenticationFilter.class). ...

Ответ принят как подходящий

Почему вы видите исключение NullPointerException

Вы видите NullPointerException, потому что у вас нет AuthenticationManager, подключенного к вашему фильтру. Согласно javadocs для AbstractAuthenticationProcessingFilter

The filter requires that you set the authenticationManager property. An AuthenticationManager is required to process the authentication request tokens created by implementing classes

В этом случае я почесываю в затылке, почему authenticationManager не стал использовать аргумент конструктора для этого абстрактного фильтра. Я бы рекомендовал применить это в вашем конструкторе для вашего настраиваемого фильтра.

public MyAuthenticationFilter(AuthenticationManager authenticationManager) {
    super(new AntPathRequestMatcher("/login", "POST"));
    this.setAuthenticationManager(authenticationManager);
}

AuthenticationManager или AuthenticationProvider

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.authenticationProvider(myAuthenticationProvider);
}

AuthenticationManagerBuilder создаст ProviderManager (an AuthenticationManager).

ProviderManager представляет собой набор AuthenticationProvider и будет пытаться подключиться к authenticate() с каждым AuthenticationProvider, которым он управляет. (Вот где public boolean supports(Class<?> authentication) чрезвычайно важен в контракте AuthenticationProvider)

В вашей конфигурации вы создали ProviderManager, содержащий только ваш собственный Authentication Provider.

Прохладный. Где теперь мой AuthenticationManager?

Можно взять AuthenticationManager, построенный методом configure(), с помощью this.authenticationManager() в WebSecurityConfigurerAdapter.

@Bean
public AuthenticationManager authenticationManager throws Exception() {
    this.authenticationManager();
}

Рекомендации

Создание вашего собственного ProviderManager действительно имеет свои преимущества, поскольку это будет явным и под вашим контролем.

@Bean
public AuthenticationManager authenticationManager() {
    return new ProviderManager(Arrays.asList(myAuthenticationProvider));
}

Это позволит вам гибко подходить к размещению вашего bean-компонента AuthenticationManager и избежать:

  • Возможные проблемы с циклической зависимостью в конфигурациях вашего bean-компонента
  • Заполнение проверенного Exception в результате вызова this.authenticationManager()

Собираем все вместе

...
public class AppConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    MyAuthenticationProvider myAuthenticationProvider;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.addFilterBefore(new MyAuthenticationFilter(authenticationManager()), BasicAuthenticationFilter.class)
        ...
    }

    @Bean
    public AuthenticationManager authenticationManager() {
        return new ProviderManager(Arrays.asList(myAuthenticationProvider));
    }
}

Дополнительная точка отсчета: AuthenticationManager против AuthenticationProvider

shinjw 24.08.2018 11:17

Большое спасибо! Я, очевидно, не уделил достаточно внимания при чтении документа, но все же ваш ответ, вероятно, был необходим, поскольку я не знал бы подходящего места, чтобы собрать все вместе. Как я вижу в документе, ProviderManager - единственная реализация для AuthenticationManager; имеет ли смысл для моего примера написать собственную реализацию AuthenticationManager или это довольно необычно? Я, кстати, всегда благодарен за дополнительные рекомендации, как вы написали; это помогает установить лучшее контекстное знание, так что спасибо за это.

Wolfone 25.08.2018 10:37

Учитывая, что у вас только один AuthenticationProvider, у вас есть возможность предоставить реализацию AuthenticationManager. ProviderManager предназначен для работы по разным стратегиям.

shinjw 25.08.2018 23:24

Понятно, хотя это не кажется чрезмерно необходимым; Спасибо!

Wolfone 10.09.2018 11:54

Другие вопросы по теме