Spring Boot 2.7.7中MockMvc自定义认证注入异常问题排查
为什么会出现这个问题?
1. 参数解析逻辑的优先级冲突
当控制器方法参数没有注解时,Spring MVC会通过Spring Security提供的参数解析器(比如AuthenticationPrincipalArgumentResolver)从SecurityContext里直接取出当前的认证对象,匹配到你的CustomAuthenticationToken类型后返回真实的MockCustomAuthenticationToken实例。
但如果给参数加上@Autowired,Spring会直接切换到依赖注入逻辑:它会去Spring容器里找CustomAuthenticationToken类型的Bean。而你只是在测试时通过@WithCustomAuthenticationToken把实例存入SecurityContext,并没有把它注册成容器Bean,所以Spring会为这个接口生成一个JDK动态代理(就是你看到的jdk.proxy2.$Proxy123),这个代理没有绑定任何真实实例数据,自然是空对象。
至于@ApiIgnore,它本身是Swagger的注解,正常不该影响参数解析,但如果你的项目里有自定义的参数解析逻辑对@ApiIgnore做了特殊处理,或者Swagger的解析器干扰了Spring MVC默认的参数解析优先级,会导致Spring误判为需要用DI逻辑处理这个参数,最终同样生成空代理。
2. 通用Authentication参数不受影响的原因
通用Authentication参数不管加不加注解都能正常工作,是因为:
- 不加注解时,参数解析器直接从
SecurityContext取到实例,类型匹配; - 加注解时,即使Spring尝试DI,容器里没有
Authentication类型的Bean,但部分场景下Spring Security的参数解析器优先级更高,还是会从SecurityContext取数据,所以不会生成空代理。
解决办法
移除参数上的多余注解:
CustomAuthenticationToken是从SecurityContext获取的认证对象,根本不需要@Autowired(它不是容器管理的Bean);如果是为了让Swagger忽略这个参数,别直接加@ApiIgnore在参数上,可以通过Swagger的全局配置或者接口级别的忽略规则来实现,避免干扰Spring的参数解析逻辑。自定义参数解析器(可选):
如果必须保留注解(比如有特殊业务需求),可以自定义一个HandlerMethodArgumentResolver,指定当参数是CustomAuthenticationToken且带有目标注解时,直接从SecurityContext中获取实例,覆盖Spring的DI解析逻辑。排查Swagger配置:
如果是@ApiIgnore导致的问题,检查项目里有没有自定义的Swagger参数处理器,确保它不会改变Spring MVC默认的参数解析优先级。
内容的提问来源于stack exchange,提问作者JayTheKay

