无需引入Spring-MVC依赖,自定义HandlerMethodArgumentResolver实现@AuthenticationId
解决自定义@AuthenticationId注解的实现问题
嘿,我来帮你理一理这个问题——首先得澄清一个关键点:@RestController本身就属于Spring Web模块(不管是传统的Servlet MVC还是响应式的WebFlux),所以你说的“未依赖Spring-MVC”大概率是个误解:要么你已经通过spring-boot-starter-web间接引入了Spring MVC,要么你用的是Spring WebFlux(这时候对应的参数解析器体系和MVC略有不同,但依然支持自定义实现)。
下面分两种场景给你具体的实现方案:
场景一:你的项目基于Spring MVC(比如用了spring-boot-starter-web)
这种情况下,完全可以通过自定义HandlerMethodArgumentResolver实现你的需求,不需要额外引入依赖,步骤如下:
1. 定义@AuthenticationId注解
@Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) public @interface AuthenticationId { }
2. 实现参数解析器
public class AuthenticationIdArgumentResolver implements HandlerMethodArgumentResolver { @Override public boolean supportsParameter(MethodParameter parameter) { // 判断参数是否标注了@AuthenticationId return parameter.hasParameterAnnotation(AuthenticationId.class); } @Override public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { // 从安全上下文获取认证信息 Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); if (authentication == null || !(authentication.getPrincipal() instanceof YourCustomPrincipal)) { throw new IllegalArgumentException("当前请求不存在有效的自定义Principal"); } // 提取并返回id字段 YourCustomPrincipal customPrincipal = (YourCustomPrincipal) authentication.getPrincipal(); return customPrincipal.getId(); } }
注意替换YourCustomPrincipal为你实际的自定义Principal类。
3. 注册参数解析器
通过WebMvcConfigurer把自定义解析器加入Spring MVC的处理链:
@Configuration public class WebMvcConfig implements WebMvcConfigurer { @Override public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) { resolvers.add(new AuthenticationIdArgumentResolver()); } }
4. 实际使用
现在你就可以在Controller方法里直接用这个注解了:
@RestController @RequestMapping("/api") public class DemoController { @GetMapping("/user") public ResponseEntity<String> getUserInfo(@AuthenticationId Long userId) { return ResponseEntity.ok("当前用户ID:" + userId); } }
场景二:你的项目基于Spring WebFlux
如果用的是响应式WebFlux,参数解析器的实现和注册方式略有不同,但核心逻辑一致:
1. 同样先定义@AuthenticationId注解
和场景一的注解代码完全一样。
2. 实现WebFlux版本的参数解析器
public class AuthenticationIdArgumentResolver implements HandlerMethodArgumentResolver { @Override public boolean supportsParameter(MethodParameter parameter) { return parameter.hasParameterAnnotation(AuthenticationId.class); } @Override public Object resolveArgument(MethodParameter parameter, BindingContext bindingContext, ServerWebExchange exchange) { Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); if (authentication == null || !(authentication.getPrincipal() instanceof YourCustomPrincipal)) { throw new IllegalArgumentException("当前请求不存在有效的自定义Principal"); } YourCustomPrincipal customPrincipal = (YourCustomPrincipal) authentication.getPrincipal(); return customPrincipal.getId(); } }
3. 注册到WebFlux配置
@Configuration public class WebFluxConfig implements WebFluxConfigurer { @Override public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) { resolvers.add(new AuthenticationIdArgumentResolver()); } }
额外小技巧:无需自定义注解的简化方案
如果你只是想简化获取id的代码,其实不用自定义解析器也能做到——直接用@AuthenticationPrincipal的expression属性:
@GetMapping("/user") public ResponseEntity<String> getUserInfo(@AuthenticationPrincipal(expression = "id") Long userId) { return ResponseEntity.ok("当前用户ID:" + userId); }
这种方式更轻量,适合不需要复用注解的场景。
内容的提问来源于stack exchange,提问作者Herr Derb
相关产品推荐
相关产品推荐

