Spring Boot Reactive应用JWT认证后用户存储问题求助
问题1:过滤器执行两次的解决办法
替换自定义过滤器为认证成功处理器
你当前自行解析JWT的方式既未验证签名等安全信息,又容易因过滤器重复触发导致重复执行。Spring Security OAuth2 Resource Server已完成JWT的验证与解析,直接利用原生的认证成功回调即可避免重复执行:修改
SecurityConfiguration:@EnableWebFluxSecurity @EnableReactiveMethodSecurity @Slf4j @RequiredArgsConstructor public class SecurityConfiguration { private final UserSavingAuthenticationSuccessHandler successHandler; @Bean SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { http.authorizeExchange() .anyExchange().authenticated() .and() .oauth2ResourceServer() .jwt() .authenticationSuccessHandler(successHandler); return http.build(); } }实现
ServerAuthenticationSuccessHandler处理用户存储
该处理器仅在认证成功时触发一次,从Spring Security已解析的认证对象中获取用户信息:@Component @Slf4j @RequiredArgsConstructor public class UserSavingAuthenticationSuccessHandler implements ServerAuthenticationSuccessHandler { private final UserService userService; @Override public Mono<Void> onAuthenticationSuccess(WebFilterExchange webFilterExchange, Authentication authentication) { if (authentication instanceof JwtAuthenticationToken jwtToken) { Jwt jwt = jwtToken.getToken(); String email = jwt.getClaimAsString("email"); String firstName = jwt.getClaimAsString("given_name"); String lastName = jwt.getClaimAsString("family_name"); return userService.existsByEmail(email) .flatMap(exists -> { if (exists) { return Mono.empty(); } User user = new User(); user.setEmail(email); user.setFirstName(firstName); user.setLastName(lastName); log.info("Saving new user with email: {}", email); return userService.save(user); }) .then(webFilterExchange.getChain().filter(webFilterExchange.getExchange())); } return webFilterExchange.getChain().filter(webFilterExchange.getExchange()); } }
问题2:getAll()无法返回本次请求存储用户的解决办法
问题根源是你之前的代码使用toFuture().get()(阻塞操作破坏响应式上下文)和subscribe()(异步操作脱离请求链条),导致存储操作与请求流程未绑定,请求返回时数据可能还未写入MongoDB。
上述ServerAuthenticationSuccessHandler的实现中,通过响应式链式调用将存储操作与请求链条绑定:
- 用
flatMap串联“检查用户是否存在→保存新用户”的逻辑 - 最后用
then()确保存储操作完成后再继续处理请求
同时确保你的UserService和Repository是响应式实现:
// UserService示例 public interface UserService { Mono<Boolean> existsByEmail(String email); Mono<User> save(User user); Flux<User> getAll(); } // Repository示例 public interface UserRepository extends ReactiveMongoRepository<User, String> { Mono<Boolean> existsByEmail(String email); }
额外优化建议
- 移除原
UserSavingFilter,依赖Spring Security的JWT解析结果,避免重复造轮子且更安全 - 永远不要在响应式代码中使用
block()、toFuture().get()等阻塞操作,会引发性能问题和上下文丢失 - 非必要不要用
subscribe()触发异步操作,需等待结果的操作必须纳入响应式链条
内容的提问来源于stack exchange,提问作者eternal
相关产品推荐
相关产品推荐

