WebFlux Security

Spring Security 的 WebFlux 支援依賴於一個 WebFilter,並且對於 Spring WebFlux 和 Spring WebFlux.Fn 的工作方式相同。一些示例應用展示了相關程式碼

最簡 WebFlux 安全配置

以下清單顯示了一個最簡 WebFlux 安全配置

最簡 WebFlux 安全配置
  • Java

  • Kotlin

@Configuration
@EnableWebFluxSecurity
public class HelloWebfluxSecurityConfig {

	@Bean
	public MapReactiveUserDetailsService userDetailsService() {
		UserDetails user = User.withDefaultPasswordEncoder()
			.username("user")
			.password("user")
			.roles("USER")
			.build();
		return new MapReactiveUserDetailsService(user);
	}
}
@Configuration
@EnableWebFluxSecurity
class HelloWebfluxSecurityConfig {

    @Bean
    fun userDetailsService(): ReactiveUserDetailsService {
        val userDetails = User.withDefaultPasswordEncoder()
                .username("user")
                .password("user")
                .roles("USER")
                .build()
        return MapReactiveUserDetailsService(userDetails)
    }
}

此配置提供了表單和 HTTP Basic 身份驗證,設定了授權以要求經身份驗證的使用者訪問任何頁面,設定了預設登入頁和預設登出頁,設定了安全相關的 HTTP 頭,添加了 CSRF 防護等等。

顯式 WebFlux 安全配置

以下頁面顯示了最簡 WebFlux 安全配置的顯式版本

顯式 WebFlux 安全配置
  • Java

  • Kotlin

@Configuration
@EnableWebFluxSecurity
public class HelloWebfluxSecurityConfig {

	@Bean
	public MapReactiveUserDetailsService userDetailsService() {
		UserDetails user = User.withDefaultPasswordEncoder()
			.username("user")
			.password("user")
			.roles("USER")
			.build();
		return new MapReactiveUserDetailsService(user);
	}

	@Bean
	public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
		http
			.authorizeExchange(exchanges -> exchanges
			    .anyExchange().authenticated()
			)
			.httpBasic(withDefaults())
			.formLogin(withDefaults());
		return http.build();
	}
}
import org.springframework.security.config.web.server.invoke

@Configuration
@EnableWebFluxSecurity
class HelloWebfluxSecurityConfig {

    @Bean
    fun userDetailsService(): ReactiveUserDetailsService {
        val userDetails = User.withDefaultPasswordEncoder()
                .username("user")
                .password("user")
                .roles("USER")
                .build()
        return MapReactiveUserDetailsService(userDetails)
    }

    @Bean
    fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
        return http {
            authorizeExchange {
                authorize(anyExchange, authenticated)
            }
            formLogin { }
            httpBasic { }
        }
    }
}
請確保匯入 org.springframework.security.config.web.server.invoke 函式以在你的類中啟用 Kotlin DSL,因為 IDE 不總是會自動匯入該方法,這可能會導致編譯問題。

此配置顯式設定了所有與最簡配置相同的內容。從這裡,你可以更容易地修改預設設定。

你可以在單元測試中找到更多顯式配置的示例,方法是在 config/src/test/ 目錄下搜尋 EnableWebFluxSecurity

多鏈支援

你可以配置多個 SecurityWebFilterChain 例項,以透過 RequestMatcher 例項來分隔配置。

例如,你可以為以 /api 開頭的 URL 隔離配置

  • Java

  • Kotlin

@Configuration
@EnableWebFluxSecurity
static class MultiSecurityHttpConfig {

    @Order(Ordered.HIGHEST_PRECEDENCE)                                                      (1)
    @Bean
    SecurityWebFilterChain apiHttpSecurity(ServerHttpSecurity http) {
        http
            .securityMatcher(new PathPatternParserServerWebExchangeMatcher("/api/**"))      (2)
            .authorizeExchange((exchanges) -> exchanges
                .anyExchange().authenticated()
            )
            .oauth2ResourceServer(OAuth2ResourceServerSpec::jwt);                           (3)
        return http.build();
    }

    @Bean
    SecurityWebFilterChain webHttpSecurity(ServerHttpSecurity http) {                       (4)
        http
            .authorizeExchange((exchanges) -> exchanges
                .anyExchange().authenticated()
            )
            .httpBasic(withDefaults());                                                     (5)
        return http.build();
    }

    @Bean
    ReactiveUserDetailsService userDetailsService() {
        return new MapReactiveUserDetailsService(
                PasswordEncodedUser.user(), PasswordEncodedUser.admin());
    }

}
import org.springframework.security.config.web.server.invoke

@Configuration
@EnableWebFluxSecurity
open class MultiSecurityHttpConfig {
    @Order(Ordered.HIGHEST_PRECEDENCE)                                                      (1)
    @Bean
    open fun apiHttpSecurity(http: ServerHttpSecurity): SecurityWebFilterChain {
        return http {
            securityMatcher(PathPatternParserServerWebExchangeMatcher("/api/**"))           (2)
            authorizeExchange {
                authorize(anyExchange, authenticated)
            }
            oauth2ResourceServer {
                jwt { }                                                                     (3)
            }
        }
    }

    @Bean
    open fun webHttpSecurity(http: ServerHttpSecurity): SecurityWebFilterChain {            (4)
        return http {
            authorizeExchange {
                authorize(anyExchange, authenticated)
            }
            httpBasic { }                                                                   (5)
        }
    }

    @Bean
    open fun userDetailsService(): ReactiveUserDetailsService {
        return MapReactiveUserDetailsService(
            PasswordEncodedUser.user(), PasswordEncodedUser.admin()
        )
    }
}
1 使用 @Order 配置 SecurityWebFilterChain,以指定 Spring Security 應首先考慮哪個 SecurityWebFilterChain
2 使用 PathPatternParserServerWebExchangeMatcher 來宣告此 SecurityWebFilterChain 將僅應用於以 /api/ 開頭的 URL 路徑
3 指定將用於 /api/** 端點的身份驗證機制
4 建立另一個優先順序較低的 SecurityWebFilterChain 例項來匹配所有其他 URL
5 指定將用於應用程式其餘部分的身份驗證機制

Spring Security 為每個請求選擇一個 SecurityWebFilterChain @Bean。它按照 securityMatcher 定義的順序匹配請求。

在這種情況下,這意味著如果 URL 路徑以 /api 開頭,Spring Security 會使用 apiHttpSecurity。如果 URL 不以 /api 開頭,Spring Security 則預設使用 webHttpSecurity,後者有一個隱含的 securityMatcher,用於匹配任何請求。