1. 概述

从 Spring Security 5.1.x GA 版本开始,官方正式支持在 WebFlux 环境下使用 OAuth2 登录功能。

本文将介绍 如何在 WebFlux 应用中配置 OAuth2 登录支持,并讲解如何使用 WebClient 来访问受 OAuth2 保护的资源。

虽然 WebFlux 的 OAuth 登录配置方式与传统的 Web MVC 类似,但如果你还不太熟悉,可以先参考我们之前的文章:Spring OAuth2Login 配置详解

2. Maven 依赖配置

首先,我们创建一个简单的 Spring Boot 项目,并在 pom.xml 中添加以下依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-oauth2-client</artifactId>
</dependency>

✅ 这些依赖都可以在 Maven Central 找到:

3. 主控制器

接下来,我们添加一个简单的控制器,用于在首页显示用户名:

@RestController
public class MainController {
    
    @GetMapping("/")
    public Mono<String> index(@AuthenticationPrincipal Mono<OAuth2User> oauth2User) {
       return oauth2User
        .map(OAuth2User::getName)
        .map(name -> String.format("Hi, %s", name));
    }
}

⚠️ 注意:这里展示的用户名是从 OAuth2 提供方的 UserInfo 接口获取的。

4. 使用 Google 登录

我们来配置应用,使其支持使用 Google 账号登录。

步骤如下:

  1. Google Developer Console 上创建一个新项目。
  2. 添加 OAuth2 凭据(选择 “Create Credentials > OAuth Client ID”)。
  3. 在 “Authorized Redirect URIs” 中添加回调地址:
http://localhost:8080/login/oauth2/code/google

然后,在 application.yml 中配置 Client ID 和 Secret:

spring:
  security:
    oauth2:
      client:
        registration:
          google:
            client-id: YOUR_APP_CLIENT_ID
            client-secret: YOUR_APP_CLIENT_SECRET

✅ 添加了 spring-security-oauth2-client 依赖后,应用会自动启用安全机制。访问首页前,用户会被重定向到 Google 登录页。

5. 使用自定义认证服务登录

我们也可以配置应用使用自定义的 OAuth2 授权服务器登录。

以下配置示例基于我们之前的一篇文章:REST API + Spring OAuth2 + AngularJS

这次我们需要配置更多属性,而不仅仅是 Client ID 和 Secret:

spring:
  security:
    oauth2:
      client:
        registration:
          custom:
            client-id: fooClientIdPassword
            client-secret: secret
            scopes: read,foo
            authorization-grant-type: authorization_code
            redirect-uri-template: http://localhost:8080/login/oauth2/code/custom
        provider:
          custom:
            authorization-uri: http://localhost:8081/spring-security-oauth-server/oauth/authorize
            token-uri: http://localhost:8081/spring-security-oauth-server/oauth/token
            user-info-uri: http://localhost:8088/spring-security-oauth-resource/users/extra
            user-name-attribute: user_name

⚠️ 注意事项:

  • 需要指定 scope、grant type 和 redirect-uri
  • 需要提供授权服务器的 authorization-uri 和 token-uri
  • 最后还需要配置 UserInfo 接口,以便获取用户信息

6. 安全配置

默认情况下,Spring Security 会保护所有路径。如果只配置了一个 OAuth2 客户端,则会自动跳转到该客户端进行登录。

如果配置了多个客户端,Spring Security 会自动生成一个登录选择页面。

当然,你也可以自定义安全策略。比如:

@EnableWebFluxSecurity
public class SecurityConfig {

    @Bean
    public SecurityWebFilterChain configure(ServerHttpSecurity http) throws Exception {
        return http.authorizeExchange(auth -> auth
                .pathMatchers("/about").permitAll()
                .anyExchange().authenticated())
                .oauth2Login(Customizer.withDefaults())
                .build();
    }
}

✅ 在这个例子中,除了 /about 外的所有路径都需要认证。

7. WebClient 使用

OAuth2 不仅可以用来做登录,还可以结合 WebClient 访问受保护的资源。

配置 WebClient

@Bean
public WebClient webClient(ReactiveClientRegistrationRepository clientRegistrationRepo, 
  ServerOAuth2AuthorizedClientRepository authorizedClientRepo) {
    ServerOAuth2AuthorizedClientExchangeFilterFunction filter = 
      new ServerOAuth2AuthorizedClientExchangeFilterFunction(clientRegistrationRepo, authorizedClientRepo);
    
    return WebClient.builder().filter(filter).build();
}

调用受保护资源

@Autowired
private WebClient webClient;

@GetMapping("/foos/{id}")
public Mono<Foo> getFooResource(@RegisteredOAuth2AuthorizedClient("custom") 
  OAuth2AuthorizedClient client, @PathVariable final long id){
    return webClient
      .get()
      .uri("http://localhost:8088/spring-security-oauth-resource/foos/{id}", id)
      .attributes(oauth2AuthorizedClient(client))
      .retrieve()
      .bodyToMono(Foo.class); 
}

✅ 注意:这里我们使用 OAuth2AuthorizedClient 中的 Access Token 来调用远程接口。

8. 总结

这篇文章中,我们介绍了如何在 WebFlux 应用中集成 OAuth2 登录,并演示了如何使用 WebClient 调用 OAuth2 保护的资源。

📌 完整代码可参考 GitHub 仓库:Spring Reactive OAuth 示例


原始标题:Spring Security OAuth Login with WebFlux | Baeldung