Spring Boot Oauth2, не могу отправить clientId из клиента javascript - PullRequest
0 голосов
/ 27 июня 2018

Моя проблема в очень кратком описании в том, что я не могу отправить идентификатор клиента, настроенный мной из веб-клиента.

В деталях:

Я создал простой сервер oauth2 с весенней загрузкой. Сервер работает отлично, как и ожидалось, я запрашиваю токен, отправляя учетные данные пользователя, и получаю токен, отправляя почтовый запрос с использованием почтальона как:

trusted-app@localhost:8080/oauth/token

Обратите внимание, я отправляю клиенту trusted-app идентификатор как часть URL!

Успешный ответ:

{
    "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsib2F1dGgyX2FwcGxpY2F0aW9uIl0sInVzZXJfbmFtZSI6ImFkbWluIiwic2NvcGUiOlsicmVhZCIsIndyaXRlIiwidXNlcl9pbmZvIl0sImV4cCI6MTUzMDA5Njg5OSwiYXV0aG9yaXRpZXMiOlsiUk9MRV9SRUdJU1RFUiIsIlJPTEVfQURNSU4iXSwianRpIjoiZTZjMjdlYmItN2ZkNC00MzU2LWFmYzgtNmQ5NTk4M2YwMWE0IiwiY2xpZW50X2lkIjoiQ2xpZW50SWQifQ.Xsi-9J7R5oeiaa29VAYgtLYFB971VMRLKAwpTYz0gNI",
    "token_type": "bearer",
    "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsib2F1dGgyX2FwcGxpY2F0aW9uIl0sInVzZXJfbmFtZSI6ImFkbWluIiwic2NvcGUiOlsicmVhZCIsIndyaXRlIiwidXNlcl9pbmZvIl0sImF0aSI6ImU2YzI3ZWJiLTdmZDQtNDM1Ni1hZmM4LTZkOTU5ODNmMDFhNCIsImV4cCI6MTUzMjY0NTY5OSwiYXV0aG9yaXRpZXMiOlsiUk9MRV9SRUdJU1RFUiIsIlJPTEVfQURNSU4iXSwianRpIjoiNzI5ZDViMDctN2E0Yy00MmEyLWEzYTQtMTk2MTY0YWU2YmNmIiwiY2xpZW50X2lkIjoiQ2xpZW50SWQifQ.QgNg7LwYs8M4UuBW1ntkqHPGugqFIbHG8XQUPARWq3M",
    "expires_in": 43199,
    "scope": "read write user_info",
    "jti": "e6c27ebb-7fd4-4356-afc8-6d95983f01a4"
}

Моя проблема заключается в отправке одного и того же запроса из кода JavaScript, с использованием любой клиентской библиотеки JavaScript, JQuery / Axios или чего-либо еще, я всегда получаю сообщение об ошибке:

{
    "timestamp": 1530058939432,
    "status": 401,
    "error": "Unauthorized",
    "message": "Full authentication is required to access this resource",
    "path": "/oauth/token"
}
  • Я также получаю ту же ошибку на почтальоне, если я запросил с неправильным идентификатор клиента или без идентификатора клиента.
  • Проверяя логи сети Chrome, я вижу, что запрос всегда отправляется без идентификатора клиента!
  • Я провел много исследований и вижу другие проекты, которые отправляют идентификатор клиента в качестве параметра запроса: clientId:trusted-app, но это не сработало для меня, не как параметр запроса, не как заголовок, и не как параметр формы.

И теперь я совершенно сбит с толку, разве не разрешено отправлять идентификатор клиента в URL-адресе из веб-клиента? Есть ли способ, где я могу настроить Spring Security для чтения clientId из заголовка, запроса или параметра формы?

Вот такие

AuthorizationServerConfigurerAdapter:

    @Configuration
    @EnableAuthorizationServer
    public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

        @Value("${security.oauth2.resource.id}")
        private String resourceId;

        @Value("${access_token.validity_period}")
        private int accessTokenValiditySeconds;

        @Value("${refresh_token.validity_period}")
        private int refreshTokenValiditySeconds;

        @Autowired
        private AuthenticationManager authenticationManager;

        @Autowired
        private SecretKeyProvider keyProvider;

        @Bean
        public UserDetailsService userDetailsService() {
            return new AccountServiceImpl();
        }

        @Override
        public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
            endpoints
                    .authenticationManager(authenticationManager)
                    .tokenServices(tokenServices())
                    .tokenStore(tokenStore())
                    .accessTokenConverter(accessTokenConverter());
        }

        @Override
        public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
            oauthServer.tokenKeyAccess("permitAll()")
                    .checkTokenAccess("isAuthenticated()");
        }

        @Override
        public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
            clients.inMemory()
                    .withClient("trusted-app")
                    .authorizedGrantTypes("authorization_code", "implicit", "client_credentials", "password", "refresh_token")
                    .authorities("ROLE_TRUSTED_CLIENT")
                    .scopes("read", "write", "user_info")
                    .resourceIds(resourceId)
                    .accessTokenValiditySeconds(accessTokenValiditySeconds)
                    .refreshTokenValiditySeconds(refreshTokenValiditySeconds)
                    .autoApprove(true);
        }

        @Bean
        public TokenStore tokenStore() {
            return new JwtTokenStore(accessTokenConverter());
        }

        @Bean
        public JwtAccessTokenConverter accessTokenConverter() {
            JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
            try {
                converter.setSigningKey(keyProvider.getKey());
            } catch (URISyntaxException | KeyStoreException | NoSuchAlgorithmException | IOException | UnrecoverableKeyException | CertificateException e) {
                e.printStackTrace();
            }

            return converter;
        }

        @Bean
        @Primary
        public DefaultTokenServices tokenServices() {
            DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
            defaultTokenServices.setTokenStore(tokenStore());
            defaultTokenServices.setSupportRefreshToken(true);
            defaultTokenServices.setTokenEnhancer(accessTokenConverter());
            return defaultTokenServices;
        }
    }

И адаптер WebSecurityConfigurer:

@Configuration
@EnableWebSecurity(debug = true)
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private BCryptPasswordEncoder bCryptPasswordEncoder;

    @Bean
    public DaoAuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
        provider.setPasswordEncoder(bCryptPasswordEncoder);
        provider.setUserDetailsService(userDetailsService);
        return provider;
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
                .userDetailsService(userDetailsService)
                .passwordEncoder(bCryptPasswordEncoder);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .csrf().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER)
                .and()
                .authorizeRequests()
                .antMatchers("/oauth/token").anonymous()
                .and()
                .authorizeRequests()
                .anyRequest().authenticated();
    }

    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web
                .ignoring()
                .antMatchers("/resources/**", "/static/**", "/css/**", "/js/**", "/images/**");
    }
}

Пока я разделяю только эти два класса, потому что я считаю, что нужное мне решение можно исправить только здесь, и я могу ошибаться.

1 Ответ

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

Вы можете настроить сервер авторизации так, чтобы клиент мог проходить аутентификацию через данные формы, как показано ниже,

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

  @Override
    public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
        oauthServer.allowFormAuthenticationForClients();
    }
}

Тогда либо вы можете отправить как данные формы

curl -X POST \
  http://localhost:54040/oauth/token \
  -H 'content-type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW' \
  -F grant_type=system \
  -F username=udara \
  -F password=udara123 \
  -F client_id=wfw3e5454353wwrwrtr \
  -F client_secret=432fwrw5425242543w245325

или в формате x-www-form-urlencoded

curl -X POST \
  http://localhost:54040/oauth/token \

  -H 'Content-Type: application/x-www-form-urlencoded'  \
  -d 'grant_type=internal&username=udara&password=udara123&client_id=wfw3e5454353wwrwrtr&client_secret=432fwrw5425242543w245325'
...