Spring Boot Webflux @PreAuthorize的SpEL传参始终为null问题求助
我在Spring Boot 3.2.2结合Webflux Security的项目中,尝试通过ReactiveMethodSecurity自定义@PreAuthorize权限校验,用于检查用户对"space"的访问权限。自定义校验类代码如下:
@Component(value = "SpaceAccess") @RequiredArgsConstructor @Slf4j public class SpaceAccessValidation { public final Mono<Boolean> readable(String spaceId){ log.info("spaceId: {}", spaceId); Mono<Boolean> access = AuthUtils.getMemberDetailsMono() .map(memberDetails -> memberDetails.spaces() .stream() .anyMatch(o -> StringUtils.equals(o.id(), spaceId) && o.role().readable)) .switchIfEmpty(AuthUtils.getAccessId() .flatMap(accessId -> compareSpaceMemberRoleLevel(spaceId, accessId, SpaceRoleType.VIEWER)) ); return Mono.zip(access, spaceExist(spaceId), (a, b) -> a && b); } }
AuthUtils用于从ReactiveSecurityContextHolder获取主体信息。但调用RestController接口时,传入的spaceId始终为null,接口代码如下:
@RestController @RequestMapping("search/spaces/{spaceId}") public class SearchRestController { @GetMapping("memos") @PreAuthorize("@SpaceAccess.readable(#spaceId)") @ResponseStatus(HttpStatus.OK) public Mono<PagingResultRecord> findMemos(@PathVariable(name = "spaceId") String spaceId){ // 业务逻辑 } }
调用API时,SpEL表达式#spaceId始终传递null值,查阅文档确认动态传参用#variable是正确的,求解决办法。
解决方案
1. 编译时保留参数名称
Java默认编译会丢失方法参数名,导致SpEL无法识别#spaceId。需要在构建工具中开启-parameters编译选项:
- Maven:在pom.xml的maven-compiler-plugin中添加配置
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.11.0</version> <configuration> <parameters>true</parameters> <source>17</source> <!-- 对应你的JDK版本 --> <target>17</target> </configuration> </plugin>
- Gradle:在build.gradle中添加
tasks.withType(JavaCompile) { options.parameters = true }
2. 改用#root.args直接引用参数
在WebFlux的响应式方法安全场景下,直接引用参数名可能存在上下文传递问题,可以通过#root.args按索引获取参数:
修改接口的@PreAuthorize注解:
@PreAuthorize("@SpaceAccess.readable(#root.args[0])")
这里#root.args[0]对应方法的第一个参数,也就是spaceId。
3. 给参数添加@Param注解显式指定名称
在接口方法的参数上添加org.springframework.data.repository.query.Param注解,显式告诉SpEL参数的名称:
@GetMapping("memos") @PreAuthorize("@SpaceAccess.readable(#spaceId)") @ResponseStatus(HttpStatus.OK) public Mono<PagingResultRecord> findMemos( @PathVariable(name = "spaceId") @Param("spaceId") String spaceId ){ // 业务逻辑 }
4. 确认ReactiveMethodSecurity配置正确
确保已经在配置类上添加@EnableReactiveMethodSecurity注解,开启响应式方法安全支持:
@Configuration @EnableReactiveMethodSecurity public class SecurityConfig { // 其他安全配置 }
内容的提问来源于stack exchange,提问作者Cerakoted
相关产品推荐
相关产品推荐

