如何通过编程获取指定VERB+PATH端点@PreAuthorize注解中的SpEL?
当然可以!在Spring生态环境下,我们完全可以通过编程手段提取指定请求端点上@PreAuthorize注解中的SpEL表达式,下面是具体的实现思路和代码示例:
核心思路
Spring Security的@PreAuthorize注解通常标注在控制器方法或类上,而Spring的RequestMappingHandlerMapping组件会维护所有请求映射与处理器方法的关联关系。我们的核心逻辑就是:找到对应请求方式(VERB)和路径(PATH)的处理器方法,再从方法或其所在类上提取@PreAuthorize的SpEL内容。
具体实现步骤与代码示例
下面以Spring Boot环境为例,写一个可直接复用的提取工具类:
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.stereotype.Component; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.servlet.mvc.method.RequestMappingInfo; import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; import java.lang.reflect.Method; import java.util.Set; @Component public class PreAuthorizeSpelExtractor { private final RequestMappingHandlerMapping requestMappingHandlerMapping; @Autowired public PreAuthorizeSpelExtractor(RequestMappingHandlerMapping requestMappingHandlerMapping) { this.requestMappingHandlerMapping = requestMappingHandlerMapping; } public String extractSpelForEndpoint(RequestMethod requestMethod, String path) { // 构造目标请求的映射信息,用于匹配端点 RequestMappingInfo targetMapping = RequestMappingInfo.paths(path) .methods(requestMethod) .build(); // 遍历所有已注册的请求映射 Set<RequestMappingInfo> allMappings = requestMappingHandlerMapping.getHandlerMethods().keySet(); for (RequestMappingInfo mapping : allMappings) { if (mapping.equals(targetMapping)) { // 获取对应的处理器方法(这里默认取第一个匹配的方法,多实例场景可按需调整) Method handlerMethod = requestMappingHandlerMapping.getHandlerMethods().get(mapping).get(0).getMethod(); // 优先检查方法上的@PreAuthorize注解 PreAuthorize methodAnnotation = handlerMethod.getAnnotation(PreAuthorize.class); if (methodAnnotation != null) { return methodAnnotation.value(); } // 方法上没有的话,检查类级别的注解 PreAuthorize classAnnotation = handlerMethod.getDeclaringClass().getAnnotation(PreAuthorize.class); if (classAnnotation != null) { return classAnnotation.value(); } break; } } // 未找到注解时返回null,也可根据需求返回空字符串 return null; } }
关键说明
- 匹配精度:如果你的应用存在多个匹配同一路径但不同
produces/consumes的端点,示例中只取第一个匹配项,实际使用时可以通过RequestMappingInfo的其他属性(如producesCondition)做更精确的过滤; - 类级别注解:代码中会先检查方法上的注解,再检查类上的——因为方法级别的注解优先级高于类级别;
- WebFlux适配:如果是Spring WebFlux项目,只需替换为
org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerMapping,核心逻辑完全一致; - 动态端点:如果是运行时动态注册的端点,需要确保在端点注册完成后再调用这个工具方法,否则可能无法匹配到。
这样就能轻松拿到指定端点的@PreAuthorize SpEL表达式了,要是你有特殊场景需要调整,随时可以基于这个核心逻辑扩展~
内容的提问来源于stack exchange,提问作者TheOni
相关产品推荐
相关产品推荐

