Spring 仅使用客户端凭据的安全端点(基本)
Spring secure endpoint with only client credentials (Basic)
我有一个带有一个自定义端点的 oauth2 授权服务器(以管理员身份手动注销特定用户)
我希望使用其余客户端凭据(客户端 ID 和密码作为基本编码 header 值)保护此端点,类似于 /oauth/check_token.
此端点只能从我的具有特定范围的资源服务器调用。
- 我需要检查客户端是否已通过身份验证。
- 我希望能够在控制器的方法上添加 @PreAuthorize("#oauth2.hasScope('TEST_SCOPE')")。
我找不到任何文档或方法来使用 Spring 的客户端身份验证检查机制。
编辑 1
我使用 java 配置而不是 xml 配置
@PreAuthorize("#oauth2.hasScope('TEST_SCOPE')")
在控制器上的方法应该足够了。如果客户端未通过身份验证,则没有可用范围,范围检查将失败。
如果需要,您可以使用 Spring 安全表达式 @PreAuthorize("isAuthenticated()")
检查客户端是否已通过身份验证:https://docs.spring.io/spring-security/site/docs/5.0.0.RELEASE/reference/htmlsingle/#el-common-built-in
您也可以配置 HttpSecurity
而不是使用 @PreAuthorize
所以我得到了以下解决方案
身份验证管理器
public class ClientAuthenticationManager implements AuthenticationManager {
private ClientDetailsService clientDetailsService;
private PasswordEncoder passwordEncoder;
public HGClientAuthenticationManager(ClientDetailsService clientDetailsService, PasswordEncoder passwordEncoder) {
Assert.notNull(clientDetailsService, "Given clientDetailsService must not be null!");
Assert.notNull(passwordEncoder, "Given passwordEncoder must not be null!");
this.clientDetailsService = clientDetailsService;
this.passwordEncoder = passwordEncoder;
}
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
ClientDetails clientDetails = null;
try {
clientDetails = this.clientDetailsService.loadClientByClientId(authentication.getPrincipal().toString());
} catch (ClientRegistrationException e) {
throw new BadCredentialsException("Invalid client id or password");
}
if (!passwordEncoder.matches(authentication.getCredentials().toString(), clientDetails.getClientSecret())) {
throw new BadCredentialsException("Invalid client id or password");
}
return new OAuth2Authentication(
new OAuth2Request(null, clientDetails.getClientId(), clientDetails.getAuthorities(), true,
clientDetails.getScope(), clientDetails.getResourceIds(), null, null, null),
null);
}
}
过滤器声明
private BasicAuthenticationFilter basicAuthenticationFilter() {
ClientDetailsUserDetailsService clientDetailsUserDetailsService = new ClientDetailsUserDetailsService(
this.clientDetailsService);
clientDetailsUserDetailsService.setPasswordEncoder(this.passwordEncoder);
return new BasicAuthenticationFilter(
new ClientAuthenticationManager(this.clientDetailsService, this.passwordEncoder));
}
过滤注册
httpSecurity.addFilterBefore(this.basicAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
警告!!!
这将阻止任何其他类型的身份验证(oauth2 等)。
ONLY Basic
身份验证被接受并且 ONLY 用于注册客户。
我有一个带有一个自定义端点的 oauth2 授权服务器(以管理员身份手动注销特定用户) 我希望使用其余客户端凭据(客户端 ID 和密码作为基本编码 header 值)保护此端点,类似于 /oauth/check_token.
此端点只能从我的具有特定范围的资源服务器调用。
- 我需要检查客户端是否已通过身份验证。
- 我希望能够在控制器的方法上添加 @PreAuthorize("#oauth2.hasScope('TEST_SCOPE')")。
我找不到任何文档或方法来使用 Spring 的客户端身份验证检查机制。
编辑 1
我使用 java 配置而不是 xml 配置
@PreAuthorize("#oauth2.hasScope('TEST_SCOPE')")
在控制器上的方法应该足够了。如果客户端未通过身份验证,则没有可用范围,范围检查将失败。
如果需要,您可以使用 Spring 安全表达式 @PreAuthorize("isAuthenticated()")
检查客户端是否已通过身份验证:https://docs.spring.io/spring-security/site/docs/5.0.0.RELEASE/reference/htmlsingle/#el-common-built-in
您也可以配置 HttpSecurity
而不是使用 @PreAuthorize
所以我得到了以下解决方案
身份验证管理器
public class ClientAuthenticationManager implements AuthenticationManager {
private ClientDetailsService clientDetailsService;
private PasswordEncoder passwordEncoder;
public HGClientAuthenticationManager(ClientDetailsService clientDetailsService, PasswordEncoder passwordEncoder) {
Assert.notNull(clientDetailsService, "Given clientDetailsService must not be null!");
Assert.notNull(passwordEncoder, "Given passwordEncoder must not be null!");
this.clientDetailsService = clientDetailsService;
this.passwordEncoder = passwordEncoder;
}
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
ClientDetails clientDetails = null;
try {
clientDetails = this.clientDetailsService.loadClientByClientId(authentication.getPrincipal().toString());
} catch (ClientRegistrationException e) {
throw new BadCredentialsException("Invalid client id or password");
}
if (!passwordEncoder.matches(authentication.getCredentials().toString(), clientDetails.getClientSecret())) {
throw new BadCredentialsException("Invalid client id or password");
}
return new OAuth2Authentication(
new OAuth2Request(null, clientDetails.getClientId(), clientDetails.getAuthorities(), true,
clientDetails.getScope(), clientDetails.getResourceIds(), null, null, null),
null);
}
}
过滤器声明
private BasicAuthenticationFilter basicAuthenticationFilter() {
ClientDetailsUserDetailsService clientDetailsUserDetailsService = new ClientDetailsUserDetailsService(
this.clientDetailsService);
clientDetailsUserDetailsService.setPasswordEncoder(this.passwordEncoder);
return new BasicAuthenticationFilter(
new ClientAuthenticationManager(this.clientDetailsService, this.passwordEncoder));
}
过滤注册
httpSecurity.addFilterBefore(this.basicAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
警告!!!
这将阻止任何其他类型的身份验证(oauth2 等)。
ONLY Basic
身份验证被接受并且 ONLY 用于注册客户。