You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

无需引入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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 08:43:06