Spring WebFlux如何实现分路径差异化认证失败响应配置
Spring WebFlux 实现分路径差异化认证失败处理
原有业务规则
- 系统基于Session Cookie完成请求身份校验
- 匹配
/api/**的请求认证失败时,直接返回401状态码供前端拦截处理 - 非
/api/**路径的请求认证失败时,服务端返回登录页引导用户登录
原有Spring MVC实现参考
@Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .anyRequest() .authenticated() .and() .formLogin() .and() .csrf() .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()) .and() .exceptionHandling() .defaultAuthenticationEntryPointFor( new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED), new AntPathRequestMatcher("/api/**") ) .and() .cors(); } }
WebFlux迁移问题
WebFlux环境下的ServerHttpSecurity没有提供Servlet环境中defaultAuthenticationEntryPointFor的直接等价方法,全局配置单一authenticationEntryPoint会导致所有路径认证失败逻辑统一,无法满足差异化处理要求,初始问题配置如下:
@Configuration @EnableWebFluxSecurity public class SecurityConfig { @Bean public SecurityWebFilterChain filterChain(ServerHttpSecurity http) { return http .authorizeExchange() .pathMatchers("/login/**") .permitAll() .anyExchange() .authenticated() .and() .formLogin() .and() .csrf() .disable() .exceptionHandling() // 全局配置401返回,导致非API路径无法跳转登录页 .authenticationEntryPoint(new HttpStatusServerEntryPoint(HttpStatus.UNAUTHORIZED)) .and() .build(); } }
实现方案
通过自定义委托型ServerAuthenticationEntryPoint,在认证失败触发时先判断请求路径,匹配对应规则后选择对应的处理逻辑即可,和MVC下多EntryPoint匹配的效果完全一致。
完整可运行配置如下:
@Configuration @EnableWebFluxSecurity public class SecurityConfig { @Bean public SecurityWebFilterChain filterChain(ServerHttpSecurity http) { // WebFlux专用路径匹配器,不要使用Servlet环境的AntPathRequestMatcher PathPatternParserServerWebExchangeMatcher apiPathMatcher = new PathPatternParserServerWebExchangeMatcher("/api/**"); // API路径认证失败处理:返回401状态码 ServerAuthenticationEntryPoint apiUnauthEntryPoint = new HttpStatusServerEntryPoint(HttpStatus.UNAUTHORIZED); // 页面路径认证失败处理:跳转登录页,路径和formLogin配置保持一致 ServerAuthenticationEntryPoint pageLoginEntryPoint = new RedirectServerAuthenticationEntryPoint("/login"); // 委托入口点:按路径分发到对应处理逻辑 ServerAuthenticationEntryPoint delegatingEntryPoint = (exchange, authEx) -> apiPathMatcher.matches(exchange) .flatMap(matchResult -> matchResult.isMatch() ? apiUnauthEntryPoint.commence(exchange, authEx) : pageLoginEntryPoint.commence(exchange, authEx) ); return http .authorizeExchange() .pathMatchers("/login/**") .permitAll() .anyExchange() .authenticated() .and() .formLogin() .and() .csrf() .disable() .cors() .exceptionHandling() .authenticationEntryPoint(delegatingEntryPoint) .and() .build(); } }
注意事项
- 路径匹配必须使用WebFlux专属的
PathPatternParserServerWebExchangeMatcher,Servlet环境的AntPathRequestMatcher在响应式环境下会出现路径匹配异常。 - 如果自定义了表单登录页路径,比如配置
.formLogin().loginPage("/custom-login"),需要同步修改RedirectServerAuthenticationEntryPoint的跳转路径为自定义登录页地址。 - 需要新增更多路径的差异化认证失败逻辑时,直接在委托入口点中增加对应匹配分支即可。
内容的提问来源于stack exchange,提问作者altair
相关产品推荐
相关产品推荐

