java - 无法使用 JSON 请求正文启用 Spring Authorization Server 令牌请求
问题描述
我正在使用 Spring Authorization Server 开发 OAuth2 授权服务器。我需要支持客户端凭据流,并且我希望客户端在 POST 请求的 JSON 请求正文中发送客户端 ID 和密码。
我的配置非常简单。它基本上是所有带有自定义的默认设置RegisteredClientRepository
:
@Configuration
@Import(OAuth2AuthorizationServerConfiguration.class)
public class AuthorizationServerConfig {
@Bean
@Primary
public RegisteredClientRepository registeredClientRepository(UserRepository repository) {
return repository;
}
}
UserRepository 中的findByClientId
方法如下所示:
@Repository
@RequiredArgsConstructor
public class UserRepository implements RegisteredClientRepository {
private final UserDao UserDao;
@Override
public RegisteredClient findByClientId(String clientId) {
return userDao.findByClientId(clientId)
.map(this::toRegisteredClient)
.orElse(null);
}
private RegisteredClient toRegisteredClient(User user) {
return RegisteredClient.withId(String.valueOf(user.getId()))
.clientName(user.getName())
.clientId(user.getClientId())
.clientSecret(user.getClientSecret())
.clientAuthenticationMethod(CLIENT_SECRET_BASIC)
.clientAuthenticationMethod(CLIENT_SECRET_POST)
.authorizationGrantType(CLIENT_CREDENTIALS)
.scope("TEST")
.clientSettings(
ClientSettings.builder().requireAuthorizationConsent(false).build()
)
.build();
}
}
假设客户 id 为user
,秘密为password
。
使用基本身份验证请求令牌有效:
curl -X POST --header "Authorization: Basic dXNlcjpwYXNzd29yZA==" http://localhost:8080/oauth2/token\?grant_type\=client_credentials
我还可以使用请求 URI 参数请求令牌:
curl -X POST http://localhost:8080/oauth2/token\?grant_type\=client_credentials\&client_id\=user\&client_secret\=password
但是,当我尝试像这样在请求正文中以 JSON 格式发送凭据时,我收到 HTTP 401 错误:
curl --header "Content-Type: application/json" -d '{"grant_type": "client_credentials", "client_id": "user", "client_secret": "password"}' http://localhost:8080/oauth2/token
这是服务器端记录的内容:
DEBUG 2021-10-18 16:04:31,287 [393-exec-4] FilterChainProxy - Securing POST /oauth2/token
DEBUG 2021-10-18 16:04:31,287 [393-exec-4] SecurityContextPersistenceFilter - Set SecurityContextHolder to empty SecurityContext
DEBUG 2021-10-18 16:04:31,287 [393-exec-4] AnonymousAuthenticationFilter - Set SecurityContextHolder to anonymous SecurityContext
DEBUG 2021-10-18 16:04:31,288 [393-exec-4] FilterSecurityInterceptor - Failed to authorize filter invocation [POST /oauth2/token] with attributes [authenticated]
DEBUG 2021-10-18 16:04:31,288 [393-exec-4] HttpSessionSecurityContextRepository - Did not store empty SecurityContext
DEBUG 2021-10-18 16:04:31,288 [393-exec-4] SecurityContextPersistenceFilter - Cleared SecurityContextHolder to complete request
我如何使它工作?
另外,为什么 Spring Authorization Server 支持将客户端凭据作为请求 URI 参数发送?OAuth 2.1 规范的第 2.3 节明确规定不得使用请求 URI 参数,因为这被认为是不安全的。
解决方案
您可以为AuthenticationConverter
您的客户端身份验证配置提供一个,如下所示:
@Bean
@Order(1)
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
OAuth2AuthorizationServerConfigurer<HttpSecurity> authorizationServerConfigurer =
new OAuth2AuthorizationServerConfigurer<>();
RequestMatcher endpointsMatcher = authorizationServerConfigurer
.getEndpointsMatcher();
authorizationServerConfigurer.clientAuthentication((clientAuth) ->
clientAuth.authenticationConverter(myCustomAuthenticationConverter()) // provide your auth converter
);
// OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http); the code above is copied from here
http
.requestMatcher(endpointsMatcher)
.authorizeRequests(authorizeRequests ->
authorizeRequests.anyRequest().authenticated()
)
.csrf(csrf -> csrf.ignoringRequestMatchers(endpointsMatcher))
.apply(authorizationServerConfigurer);
return http.formLogin(Customizer.withDefaults()).build();
}