Spring: переадресация на конечную точку / oauth / token теряет аутентификацию - PullRequest
0 голосов
/ 08 июня 2018

Я создаю сервер авторизации Spring Boot, который должен генерировать токены Oauth2 двумя разными методами аутентификации.Я хочу иметь разные конечные точки для каждого метода, но по умолчанию Spring создает только /oauth/token, и хотя его можно изменить, я не думаю, что для него можно использовать два разных пути.

В качестве альтернативы я пытаюсь создать в контроллере два метода, которые выполняют внутренний forward to /oauth/token, добавляя параметр к запросу, чтобы я мог знать, откуда он пришел.

У меня есть что-то вроде этого:

@RequestMapping(value = "/foo/oauth/token", method = RequestMethod.POST)
public ModelAndView fooOauth(ModelMap model) {
    model.addAttribute("method", "foo");
    return new ModelAndView("forward:/oauth/token", model);
}

Это выполняет пересылку правильно, но аутентификация завершается неудачно с:

There is no client authentication. Try adding an appropriate authentication filter.

Тот же запрос работает правильно при отправке на /oauth/token напрямую, поэтому я предполагаю, что проблема в том, что BasicAuthenticationFilter не работает после пересылки.

Как я могу заставить его работать?

Ответы [ 2 ]

0 голосов
/ 22 февраля 2019

У меня была точно такая же проблема.После некоторых исследований я обнаружил, что проблема была вызвана Spring Boot 2 , а не конфигурациями Spring Security.Согласно руководству по миграции Spring Boot 2.0 :

Фильтры Spring Security и Spring Session настроены для типов диспетчера ASYNC, ERROR и REQUEST.

и исходный код Spring Boot SecurityFilterAutoConfiguration :

@Bean
@ConditionalOnBean(name = DEFAULT_FILTER_NAME)
public DelegatingFilterProxyRegistrationBean securityFilterChainRegistration(
        SecurityProperties securityProperties) {
    DelegatingFilterProxyRegistrationBean registration = new DelegatingFilterProxyRegistrationBean(
            DEFAULT_FILTER_NAME);
    registration.setOrder(securityProperties.getFilter().getOrder());
    registration.setDispatcherTypes(getDispatcherTypes(securityProperties));
    return registration;
}

private EnumSet<DispatcherType> getDispatcherTypes(
        SecurityProperties securityProperties) {
    if (securityProperties.getFilter().getDispatcherTypes() == null) {
        return null;
    }
    return securityProperties.getFilter().getDispatcherTypes().stream()
            .map((type) -> DispatcherType.valueOf(type.name())).collect(Collectors
                    .collectingAndThen(Collectors.toSet(), EnumSet::copyOf));

}

По умолчанию Spring Boot настраивает Spring Security, чтобы его фильтры не применялись к запросам FORWARD(только ASYNC, ERROR и REQUEST), поэтому не будет применяться фильтр для проверки подлинности запросов перед их отправкой на /oauth/token.

Решение простое.Вы можете либо добавить следующую строку в application.properties, чтобы применить фильтры по умолчанию ко ВСЕМ перенаправленным запросам

spring.security.filter.dispatcher-types=async,error,request,forward

, либо создать собственную цепочку фильтров с сопоставителем пути и dispatcherType = FORWARD, чтобы фильтровать только запросыкоторые перенаправлены на /oauth/token.

0 голосов
/ 14 июня 2018

Внимательно следя за цепочками фильтров, созданными для конечных точек Oauth и для контроллеров пересылки, легко заметить, что в последних отсутствует BasicAuthenticationFilter, поскольку они не аутентифицированы, и аутентификация не выполняется снова после пересылки.

Чтобы решить эту проблему, я создал новую конфигурацию, подобную этой:

@Configuration
public class ForwarderSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private List<AuthorizationServerConfigurer> configurers = Collections.emptyList();

    @Autowired
    private FooClientDetailsService fooClientDetailsService;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        AuthorizationServerSecurityConfigurer configurer = new AuthorizationServerSecurityConfigurer();
        for (AuthorizationServerConfigurer configurerBit : configurers) configurerBit.configure(configurer);
        http.apply(configurer);
        http
                .authorizeRequests()
                    .antMatchers("/foo/oauth/token").fullyAuthenticated()
                .and()
                    .requestMatchers()
                    .antMatchers("/foo/oauth/token");
        http.setSharedObject(ClientDetailsService.class, fooClientDetailsService);

    }

}

Этот код имитирует то, что Spring Oauth делает за сценой ( здесь ), работая идентичнофильтровать цепочки с одинаковыми параметрами аутентификации на обеих конечных точках.

Когда конечная точка /oauth/token наконец выполняется, она находит ожидаемые результаты аутентификации и все работает.

Наконец, если вы хотитечтобы запустить другой ClientDetailsService на двух конечных точках пересылки, вам просто нужно создать два класса конфигурации, подобных этому, и заменить ClientDetailsService при вызове setSharedObject в каждой из них.Обратите внимание, что для этого вам нужно будет установить разные значения @Order в каждом классе.

...