配置 Spring Security 5 Oauth 2 以使用 access_token uri 参数

Posted

技术标签:

【中文标题】配置 Spring Security 5 Oauth 2 以使用 access_token uri 参数【英文标题】:Configure Spring Security 5 Oauth 2 to use access_token uri parameter 【发布时间】:2019-03-02 21:58:24 【问题描述】:

我正在根据这个例子创建一个应用程序-

背景 -

https://github.com/spring-projects/spring-security/tree/master/samples/boot/oauth2resourceserver-webflux

OAuth2 令牌在 Header 中可以正常工作。

问题 -

但是,我想将其更改为在 url 中使用 OAuth 2 令牌。我正在尝试创建一个 OAuth2 资源服务器。

分析-

Spring Security 似乎支持从 access_token 参数获取令牌 -

https://github.com/spring-projects/spring-security/blob/e3eaa99ad06769cf44ad3e1249f6398077b90834/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/server/ServerBearerTokenAuthenticationConverter.java#L57

不过好像默认是禁用的-

https://github.com/spring-projects/spring-security/blob/master/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/server/ServerBearerTokenAuthenticationConverter.java#L48

现在这个类在spring层级之外是不可访问的,这里直接创建-

https://github.com/spring-projects/spring-security/blob/master/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java#L955

问题?

是否可以在我的代码中将此 allowUriQueryParameter 设置为 true?

更新

我正在创建一个 OAuth2 资源服务器。不幸的是,OAuth2ResourceServerSpec 不允许设置 authenticationConverter。

【问题讨论】:

【参考方案1】:

你可以查看Spring Security的官方文档

您可以创建new ServerBearerTokenAuthenticationConverter(),在ServerHttpSecurity中设置allowUriQueryParameter一个寄存器。

@Bean
SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) 
    http
        // ...
        .oauth2Login()
            .authenticationConverter(converter) // set 
            .authenticationManager(manager)
            .authorizedClientRepository(authorizedClients)
            .clientRegistrationRepository(clientRegistrations);
    return http.build();

【讨论】:

我正在尝试创建资源服务器。不幸的是,OAuth2ResourceServerSpec 不允许设置 authenticationConverter。 你不能,基本上。唯一的方法(至少从 Spring 5 和 WebFlux 5.1.3 开始)是编写一个 WebFilter 并将查询参数转换为标题。【参考方案2】:

作为一种解决方法,您可以编写一个 WebFilter 来将 Query Parameter 转换为 Header。

【讨论】:

这没有提供问题的答案。一旦您有足够的声誉,您就可以对任何帖子发表评论;而是提供答案【参考方案3】:

Spring MVC 有很多 WebFlux 所缺乏的合理默认值。这是其中之一。

我通过设置一个 WebFilter 来解决这个问题,该过滤器在查询字符串中获取标记并将它们添加到标题中。

@Override
@NonNull
public Mono<Void> filter(
  @NonNull ServerWebExchange serverWebExchange, @NonNull WebFilterChain 
     webFilterChain) 
  ServerHttpRequest request = serverWebExchange.getRequest();
  return webFilterChain.filter(
    serverWebExchange.mutate().request(sanitizeRequest(request)).build());


private ServerHttpRequest sanitizeRequest(ServerHttpRequest request) 
  MultiValueMap<String, String> queryParams = request.getQueryParams();
  ServerHttpRequest.Builder newRequest =
    request
        .mutate()
        .headers(
            headers -> 
              if (headerContainsAuthorizationKey(headers)) 
                String token = getAuthorizationBearer(headers);
                if (token != null) 
                  // "bearer" breaks WebFlux OAuth :)
                  headers.set(HttpHeaders.AUTHORIZATION, token.replace("bearer", "Bearer"));
                  return;
                
              
              if (pathContainsAccessToken(queryParams)) 
                headers.set(
                    HttpHeaders.AUTHORIZATION,
                    "Bearer " + queryParams.getFirst("access_token"));
              
            );

  if (pathContainsAccessToken(queryParams)) 
    newRequest.uri(buildNewUriWithoutToken(request.getURI(), queryParams));
  
  return newRequest.build();
 

很高兴指出小写的“bearer”也破坏了 WebFlux。

之后,您可以在安全链中的 oauthResourceServer 规范之前添加此过滤器:

@Bean
public SecurityWebFilterChain springSecurityFilterChain(
  ServerHttpSecurity http,
  TokenStore tokenStore,
  AuthorizationHeaderFilter authorizationHeaderFilter) 
    http.csrf()
      .disable()
      .authorizeExchange()
      .anyExchange()
      .authenticated()
      .and()
      .addFilterAt(authorizationHeaderFilter, SecurityWebFiltersOrder.FIRST)
      .oauth2ResourceServer()
      .jwt() // ...  etc
  return http.build();

【讨论】:

【参考方案4】:

现在有了 Spring Security 5.1.5,我们可以做到这一点 -

ServerBearerTokenAuthenticationConverter 
authenticationConverter = new ServerBearerTokenAuthenticationConverter();
authenticationConverter.setAllowUriQueryParameter(true);

http.oauth2ResourceServer().bearerTokenConverter(authenticationConverter).jwt();

【讨论】:

我正在使用 Spring Security 5.3.3,并且这个 sn-p 的最后一行在 oauth2ResourceServer 中为 bearerTokenConverter 显示红色,因为它没有这样的成员。你知道我能做什么吗?谢谢。【参考方案5】:

Pushkar 的答案对我不起作用,但帮助我找到了解决方案,以下代码起到了作用:

DefaultBearerTokenResolver resolver = new DefaultBearerTokenResolver();
resolver.setAllowUriQueryParameter(true);

http.authorizeRequests()
        .anyRequest().authenticated()
        .and().oauth2ResourceServer().bearerTokenResolver(resolver)
        .jwt();

谢谢。

【讨论】:

在今天的Spring当前版本中,这绝对是正确的答案。 DefaultBearerTokenResolverServerBearerTokenAuthenticationConverter 共享大量代码,似乎是现代的替代品。

以上是关于配置 Spring Security 5 Oauth 2 以使用 access_token uri 参数的主要内容,如果未能解决你的问题,请参考以下文章

Spring Security - 用于多租户应用程序的 OAuth、LDAP 集成

OpenID Connect 的 Spring Security 5 XML 配置

Spring Security(十五):5.6 Authentication

配置 Spring Security 5 Oauth 2 以使用 access_token uri 参数

Spring security 5 迁移指南

在没有 servlet api 的 webflux 项目中使用 OAuth2 和 Spring Security OAuth2 和 reactor netty