仅具有客户端凭据的 Spring 安全端点(基本)

Posted

技术标签:

【中文标题】仅具有客户端凭据的 Spring 安全端点(基本)【英文标题】:Spring secure endpoint with only client credentials (Basic) 【发布时间】:2019-02-28 21:05:39 【问题描述】:

我有一个带有一个自定义端点的 oauth2 授权服务器(以管理员身份手动注销特定用户) 我希望使用其他客户端凭据(客户端 ID 和机密作为基本编码标头值)来保护此端点,类似于 /oauth/check_token。

只能从我的具有特定范围的资源服务器调用此端点。

    我需要检查客户端是否经过身份验证。 我希望能够在控制器的方法上添加@PreAuthorize("#oauth2.hasScope('TEST_SCOPE')")。

我找不到任何文档或方法来使用 Spring 的客户端身份验证检查机制。

编辑 1

我使用的是 java 配置而不是 xml 配置

【问题讨论】:

【参考方案1】:

所以我最终得到了以下解决方案

身份验证管理器

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 等)。 接受Basic身份验证并且适用于注册客户。

【讨论】:

【参考方案2】:

@PreAuthorize("#oauth2.hasScope('TEST_SCOPE')") 在控制器上的方法应该足够了。如果客户端未通过身份验证,则没有可用的范围,范围检查将失败。

如果需要,可以使用 Spring Security 表达式@PreAuthorize("isAuthenticated()") 来检查客户端是否经过身份验证:https://docs.spring.io/spring-security/site/docs/5.0.0.RELEASE/reference/htmlsingle/#el-common-built-in

您也可以配置HttpSecurity 而不是使用@PreAuthorize

【讨论】:

这可以在@EnableResourceServer 中工作,但我的问题是有问题的控制器在@EnableAuthorizationServer client_credentials 使用基本身份验证来请求 OAuth 令牌。 /oauth/check_token 端点使用令牌,而不是 clientId 和 secret。如果您愿意,可以使用与 check_token 令牌相同的机制:根据令牌加载身份验证对象。并检查身份验证对象的正确范围。你可以在这里找到 check_token 的代码:github.com/spring-projects/spring-security-oauth/blob/master/… 在调用checkToken 方法之前,已经检查了客户端身份验证。该方法不处理客户端身份验证。客户端凭据检查是通过使用 BasicAuthenticationFilterClientDetailsUserDetailsService 来完成的。

以上是关于仅具有客户端凭据的 Spring 安全端点(基本)的主要内容,如果未能解决你的问题,请参考以下文章

Spring OAuth2 安全 - 客户端凭据 - 自定义 AuthenticationProvider

spring security oauth2 client_credentials 仅流程

具有基本身份验证和 OAuth 顺序问题的 Spring Boot 安全性

Spring安全中的Oauth2客户端

春季安全过滤器问题

Spring Cloud - 如何仅允许访问特定微服务的端点?