Spring OAuth2 - аутентификации клиента нет. Попробуйте добавить соответствующий фильтр проверки подлинности

У нас есть приложение, которое использует spring-security-oauth2:1.0. Я пытался изменить его на более новую версию, spring-security-oauth2:2.0.7.RELEASE. Некоторые классы были удалены, некоторая структура пакета изменилась, мне удалось разобраться во всех этих вещах, и я смог запустить сервер без каких-либо проблем. Но здесь я сталкиваюсь со странной проблемой.

В OAuth2 - 1.0 version, когда пользователь входит в систему, мы использовали GET запрос к /oauth/token, например:

HTTP://локальный: 8080/эхо /OAuth/маркер grant_type = пароль и client_id = WS & client_secret = секрет и сфера = читать, писать и имя пользователя = джон @abc.com и пароль = password123

И раньше он работал просто отлично.

Когда я пытаюсь сделать то же самое, во-первых, я не могу сделать запрос GET из-за логики в TokenEndPoint.java

private Set<HttpMethod> allowedRequestMethods = new HashSet<HttpMethod>(Arrays.asList(HttpMethod.POST));

@RequestMapping(value = "/oauth/token", method=RequestMethod.GET)
public ResponseEntity<OAuth2AccessToken> getAccessToken(Principal principal, @RequestParam
Map<String, String> parameters) throws HttpRequestMethodNotSupportedException {
    if (!allowedRequestMethods.contains(HttpMethod.GET)) {
        throw new HttpRequestMethodNotSupportedException("GET");
    }
    return postAccessToken(principal, parameters);
}

Я попытался сделать POST запрос, такой же, как приведенный выше URL-адрес, но я получаю InsufficientAuthenticationException с сообщением об ошибке

Нет аутентификации клиента. Попробуйте добавить соответствующий фильтр аутентификации

Это из-за следующего контроллера запросов POST в TokenEndpoint.java. Когда я отлаживаю, я вижу, что principal является нулевым.

@RequestMapping(value = "/oauth/token", method=RequestMethod.POST)
    public ResponseEntity<OAuth2AccessToken> postAccessToken(Principal principal, @RequestParam
    Map<String, String> parameters) throws HttpRequestMethodNotSupportedException {
        //principal is null here
        if (!(principal instanceof Authentication)) {
            throw new InsufficientAuthenticationException(
                    "There is no client authentication. Try adding an appropriate authentication filter.");
        }
     .............
 }

У меня есть фильтр аутентификации, и он работал хорошо, когда я использовал version 1.0. Это соответствующие прароды моего конфига:

    <authentication-manager xmlns="http://www.springframework.org/schema/security">
        <authentication-provider user-service-ref="userDetailsService"/>
    </authentication-manager>

   <bean id="userDetailsService" class="com.hcl.nc.service.UserDetailsService">
        <constructor-arg><ref bean="sessionFactory" /></constructor-arg>
    </bean>

Я всегда думал, что запрос будет аутентифицирован authentication-provider и отправляется в token-endpoint но это не похоже на правильный поток. После отладки приложения с version 2.0.7 теперь я действительно сомневаюсь в своем понимании потока.

Может кто-нибудь объяснить, почему он работал в предыдущей версии и почему он не работает сейчас?

Должен ли я сделать что-то другое, чтобы получить токен OAuth?

ПРИМЕЧАНИЕ: я уже проверил эти вопросы: здесь, здесь, здесь. Но я не смог найти правильного решения.

Ответ 1

Я не знаю предыдущей версии, но я немного знаю о 2.0.7.

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

TokenEndpoint защищен BasicAuthenticationFilter. По умолчанию этот фильтр будет использовать экземпляр AuthenticationManager, который сам содержит AuthenticationProvider, который сам по себе зависит от экземпляра UserDetailsService. Фокус в том, что этот конкретный экземпляр UserDetailsService должен быть клиент, а не пользователем: почему существует ClientDetailsUserDetailsService, который адаптирует ClientDetailsService к UserDetailsService.

Обычно все это делается по умолчанию, когда вы используете классы конфигурации фрейма AuthorizationServerConfigurerAdapter, @EnableAuthorizationServer и т.д.

Ответ 2

У меня была такая же проблема, и мой application.yml имел следующую строку:

servlet:
    path: /auth

поэтому адрес токена был: /auth/oauth/token

Я удаляю путь из application.yml, чтобы путь токена стал:

/oauth/token

И все работает отлично.

Надеюсь это поможет

Ответ 3

в моем случае, я нашел эту конфигурацию:

security.allowFormAuthenticationForClients();//здесь

затем опубликуйте это   http://localhost:8081/sso/oauth/token?client_id=unity-client&client_secret=unity&grant_type=authorization_code&code=Yk4Sum&redirect_uri=http://localhost:8082/sso-demo/passport/login

его работы для меня, попробуйте

@Configuration
@EnableAuthorizationServer
public class Oauth2Config extends AuthorizationServerConfigurerAdapter {

    private static final Logger log = LoggerFactory.getLogger(Oauth2Config.class);

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security.allowFormAuthenticationForClients(); // here 
    }

    @Override
    public void configure(final ClientDetailsServiceConfigurer clients) throws Exception { // @formatter:off
        clients.inMemory()
                .withClient("unity-client")
                .secret("unity")
                .authorizedGrantTypes("authorization_code", "password", "client_credentials", "implicit", "refresh_token")
                .scopes("foo", "read", "write")
                .accessTokenValiditySeconds(3600) // 1 hour
                .refreshTokenValiditySeconds(2592000) // 30 days
        ;
    } // @formatter:on

    @Override
    public void configure(final AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
    }

}

Ответ 4

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

подтвердите это:

TokenEndpoint → метод postAccessToken. Проверьте, не является ли Принципал нулевым. Если он нулевой, это означает, что базовая аутентификация не была выполнена.

Одним из решений для добавления фильтра было использование:

@Configuration
public class FilterChainInitializer extends AbstractSecurityWebApplicationInitializer {

}

Более подробную информацию о AbstractSecurityWebApplicationInitializer можно найти в документах Spring.