如何使用SpringWebFilterChain对特定主机进行身份验证
基于请求主机匹配的Spring WebFlux Security配置
当前可通过路径模式过滤或验证请求,但需根据请求主机进行匹配。示例URL为http://localhost:8080/path,请求结构如下:
| Scheme | Host | Path |
|---|---|---|
| http:// | localhost:8080/ | demo |
目前匹配路径模式(如/get)的方法如下:
.pathMatchers(autPatterns).permitAll() .pathMatchers(securePatterns).authenticated()
Spring Security没有直接提供匹配请求主机的方法,需自定义ServerWebExchangeMatcher实现,目标是达成类似.anyExchange(exch -> matcherForHost).authenticated()的逻辑。
解决方案
修改SecurityConfig,添加自定义主机匹配器并集成到授权规则中:
package org.demo; import java.security.Key; import java.util.List; import java.util.regex.Pattern; import javax.crypto.spec.SecretKeySpec; import javax.xml.bind.DatatypeConverter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpStatus; import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; import org.springframework.security.config.web.server.ServerHttpSecurity; import org.springframework.security.web.server.SecurityWebFilterChain; import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher; import reactor.core.publisher.Mono; @Configuration @EnableWebFluxSecurity public class SecurityConfig { // 创建主机匹配器:匹配指定正则的请求主机 private ServerWebExchangeMatcher createHostMatcher(List<String> secureHostPatterns) { List<Pattern> patterns = secureHostPatterns.stream() .map(Pattern::compile) .toList(); return exchange -> { String host = exchange.getRequest().getHeaders().getFirst("Host"); if (host == null) { return Mono.just(ServerWebExchangeMatcher.MatchResult.notMatch()); } boolean matches = patterns.stream().anyMatch(p -> p.matcher(host).matches()); return matches ? Mono.just(ServerWebExchangeMatcher.MatchResult.match()) : Mono.just(ServerWebExchangeMatcher.MatchResult.notMatch()); }; } @Bean SecurityWebFilterChain springWebFilterChain(@Autowired ServerHttpSecurity http, @Autowired AuthenticationManager authenticationManager, @Autowired SecurityContextRepository securityContextRepository) { String[] autPatterns = new String[]{"/demo/auth/**"}; String[] securePatterns = new String[]{"/demo/**"}; List<String> secureHosts = List.of(".*localhost.*", ".*local\\.com.*"); // 初始化自定义主机匹配器 ServerWebExchangeMatcher hostMatcher = createHostMatcher(secureHosts); return http.cors().disable() .exceptionHandling() .authenticationEntryPoint((s, e) -> Mono.fromRunnable(() -> s.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED) )).accessDeniedHandler((s, e) -> Mono.fromRunnable(() -> s.getResponse().setStatusCode(HttpStatus.FORBIDDEN) )).and() .csrf().disable() .authenticationManager(authenticationManager) .securityContextRepository(securityContextRepository) .authorizeExchange() .pathMatchers(autPatterns).permitAll() // 组合规则:匹配指定路径且主机在列表中的请求需要认证 .pathMatchers(securePatterns).matchers(hostMatcher).authenticated() // 其余请求允许访问 .anyExchange().permitAll() .and() .build(); } }
关键说明
createHostMatcher方法:将传入的主机正则列表编译为Pattern,校验请求的Host头是否匹配任意正则,返回匹配结果。- 授权规则中使用
.pathMatchers(securePatterns).matchers(hostMatcher).authenticated(),实现路径+主机的组合校验,仅同时满足两个条件的请求需要认证。 - 若需单独基于主机匹配(不结合路径),可直接使用
.matchers(hostMatcher).authenticated()替代路径匹配规则。
内容的提问来源于stack exchange,提问作者Karthikeswar Addagalla
相关产品推荐
相关产品推荐

