如何在Netflix DGS的查询中启用@AuthenticationPrincipal参数
让@AuthenticationPrincipal在Netflix DGS组件中生效的方法
问题根源
Netflix DGS的参数解析逻辑和Spring MVC REST控制器不共享,默认不会识别并处理Spring Security的@AuthenticationPrincipal注解,直接注入时自然返回null。
解决方案
1. 自定义DGS参数解析器(推荐)
实现DgsArgumentResolver接口,专门处理带@AuthenticationPrincipal注解的参数,让DGS框架自动识别并注入认证用户信息:
@Component public class AuthenticationPrincipalArgumentResolver implements DgsArgumentResolver { @Override public boolean supportsParameter(Parameter parameter) { return parameter.isAnnotationPresent(AuthenticationPrincipal.class); } @Override public Object resolveArgument(Parameter parameter, DgsDataFetchingEnvironment environment) { Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); if (authentication == null || !(authentication.getPrincipal() instanceof UserDetails)) { return null; } return authentication.getPrincipal(); } }
将该类注册为Spring组件后,所有DgsComponent中带@AuthenticationPrincipal的参数都会自动注入UserDetails实例。
2. 简化手动获取的封装(备选)
如果不想自定义解析器,可以在方法中结合注解和上下文手动兜底,保持代码风格一致:
@DgsComponent public class YourGraphqlComponent { @DgsQuery public String getUserInfo(@AuthenticationPrincipal UserDetails userDetails) { if (userDetails == null) { Authentication auth = SecurityContextHolder.getContext().getAuthentication(); userDetails = (UserDetails) auth.getPrincipal(); } return userDetails.getUsername(); } }
3. 异步场景下的SecurityContext传播
如果你的GraphQL查询使用异步执行,需要确保SecurityContext能传递到异步线程:
@Configuration @EnableAsync public class AsyncSecurityConfig implements AsyncConfigurer { @Override public Executor getAsyncExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(5); executor.setMaxPoolSize(10); executor.setQueueCapacity(25); executor.setThreadNamePrefix("DgsAsync-"); // 传播当前认证信息到异步线程 executor.setTaskDecorator(runnable -> { Authentication auth = SecurityContextHolder.getContext().getAuthentication(); return () -> { try { SecurityContextHolder.getContext().setAuthentication(auth); runnable.run(); } finally { SecurityContextHolder.clearContext(); } }; }); executor.initialize(); return executor; } }
内容的提问来源于stack exchange,提问作者Denis Abakumov
相关产品推荐
相关产品推荐

