Spring Security 同时通过oauth服务器和API密钥进行身份验证

9njqaruj  于 2023-10-20  发布在  Spring
关注(0)|答案(2)|浏览(162)

在Sping Boot 中,是否可以使用OAuth2和API密钥对客户端进行身份验证?假设我有一个带有UI的应用程序。用户登录UI并从OAuth2服务器获得一个jwt令牌。安全配置如下所示

...
http.authorizeRequests()
    ....
    .anyRequest().authenticated().and()
    .oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt);

oauth2服务器在application.yml文件中配置。
比如说,我想向其他客户端公开一些后端API,并且只通过验证API Key来授权它们。我可以在我的安全配置中添加addFilterBefore吗?这是否意味着它将同时验证API密钥和oauth jwt?

http.addFilterBefore(new SomeApiKeyFilter(...))
    ....
    .anyRequest().authenticated().and()
    .oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt);

这可能吗?因为当我试图调用一个端点时,它抛出一个错误,说... APIKeyAuthenticationToken cannot be cast to JwtAuthenticationToken

kpbwa7wx

kpbwa7wx1#

正如@ch4mp所说,你必须定义两个安全配置。我通过在安全配置类中添加两个内部类(作为配置)而不是创建两个Bean来做到这一点。让我给你看一个例子:

public class SecurityConfig {

  @Configuration
  @Order(1)
  public static class DefaultSecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {

        http.securityMatcher("/xxx/**")
            .authorizeHttpRequests(auth -> auth
                 .anyRequest().authenticated()
            )
            ...
            .oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt);

        return http.build();
    }

  }

  @Configuration
  @Order(2)
  public static class OtherSecurityConfig {

      @Bean
    public SecurityFilterChain otherFilterChain(HttpSecurity http) throws Exception {

        http.securityMatcher("/yyy/**")
            .authorizeHttpRequests(auth -> auth
                        .anyRequest().authenticated()
            )
            .formLogin()
            ...;

        return http.build();
    }
  }

}

如果您尝试访问yyy基路径,则会收到表单登录信息;如果您尝试访问xxx基路径,则会收到401 http错误信息。

kx1ctssn

kx1ctssn2#

您的问题的表述方式反映了您的配置问题:一个请求不会同时被API密钥和Bearer访问令牌授权。它将使用一个或另一个进行授权,并且在每种情况下都应该由不同的安全过滤器链处理。
因此,不要在现有链中添加过滤器,而是向Web安全配置中添加另一个SecurityFilterChain bean。
要在一个应用程序中有多个过滤器链@Bean,它应该:

  • 具有不同的名称
  • 用不同的@Order装饰
  • 除了@Order中的最后一个之外,所有的都包含一个http.securityMatcher(...)来定义它应该处理哪些请求(@Order中的最后一个被用作所有不匹配的请求的默认值)
附1

您应该认真考虑使用OAuth2 client_credentials流,而不是API密钥,并使用单个标准OAuth2过滤器链处理由两个

  • 用户(使用authorization_code获得的令牌)
  • 程序化客户端(使用client_credentials获取令牌)

附2

您应该检查源代码中是否有JwtAuthenticationToken的显式引用,以及此APIKeyAuthenticationToken来自何处(似乎不是Spring版本的一部分,至少不是最近的版本)。如果你配置了两个安全过滤器链@Bean,并且每个都用自己的Authentication类型填充安全上下文,那么你必须使用这种身份验证多态(或使用公共的父类/接口)来编写代码。

相关问题