Spring Boot Webflux JWT授权异常:Token验证通过仍遭访问拒绝
以下是针对你遇到的问题的具体排查方向:
检查Reactive SecurityContext的传递方式
Webflux基于异步非阻塞模型,不能使用Servlet环境的SecurityContextHolder.setContext()来设置认证信息,必须通过Reactor Context传递。如果你的JwtAuthFilter里用了错误的方式设置SecurityContext,后续的拦截链或控制器无法正确获取认证信息。正确写法示例:// 在JwtAuthFilter的filter方法中 SecurityContext securityContext = SecurityContextImpl.create(authentication); return chain.filter(exchange) .contextWrite(context -> context.put(SecurityContext.class, securityContext));避免使用
SecurityContextHolder.getContext().setAuthentication(authentication);这种Servlet环境的写法。确认@EnableReactiveMethodSecurity注解已添加
Webflux环境下,必须在配置类上添加@EnableReactiveMethodSecurity才能启用方法级别的权限控制(如@PreAuthorize)。如果用了Servlet环境的@EnableMethodSecurity或未添加相关注解,@PreAuthorize的规则不会生效,或者无法正确读取Reactor Context中的SecurityContext。验证权限匹配规则与实际权限的一致性
日志显示SecurityContext中有ROLE_OWNER权限,需对应匹配正确的表达式:- 使用
hasRole("OWNER")时,Spring Security会自动给参数加上ROLE_前缀,因此实际匹配的是ROLE_OWNER,这和你的权限一致,是正确的写法。 - 使用
hasAuthority("ROLE_OWNER")时,会直接匹配权限字符串,也是正确的。
若你写的是hasRole("ROLE_OWNER"),则会匹配ROLE_ROLE_OWNER,这就会导致权限不匹配,需要检查@PreAuthorize的具体写法。
- 使用
检查SecurityWebFilterChain的过滤器顺序
确保JwtAuthFilter被添加在正确的位置,要在默认的认证过滤器之前执行。配置示例:@Bean public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) { return http .authorizeExchange(exchanges -> exchanges .pathMatchers("/login").permitAll() .anyExchange().authenticated() ) .addFilterBefore(jwtAuthFilter, SecurityWebFiltersOrder.AUTHENTICATION) .csrf(ServerHttpSecurity.CsrfSpec::disable) .build(); }如果过滤器顺序错误,后续的认证逻辑可能无法获取到JwtAuthFilter设置的SecurityContext。
确认用户权限的类型正确
加载用户详情时,需将权限字符串转换为GrantedAuthority实例(如SimpleGrantedAuthority)。如果只是存储了字符串而未转换,权限判断逻辑会因为类型不匹配而失败。示例:// 用户详情服务中构造权限集合 Collection<GrantedAuthority> authorities = user.getRoles().stream() .map(role -> new SimpleGrantedAuthority("ROLE_" + role)) .collect(Collectors.toList()); return new User(user.getUsername(), user.getPassword(), authorities);排查权限字符串的大小写问题
检查Token中解析出的权限、数据库加载的权限与@PreAuthorize中的表达式是否大小写完全一致。比如ROLE_owner和ROLE_OWNER会被视为不同的权限,导致匹配失败。
内容的提问来源于stack exchange,提问作者Azizkhuja

