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

Spring Boot GraphQL:如何在控制器方法执行前预处理单个查询/变更?

在Spring GraphQL中实现单Query/Mutation级别的权限校验

针对你要给控制器方法加注解、单独校验每个GraphQL操作(而非整个HTTP请求)的需求,Spring GraphQL提供了两种直接的实现方式:

方案1:用Spring Security原生GraphQL支持(推荐)

Spring Security对GraphQL做了专门适配,直接用@PreAuthorize注解在控制器的query/mutation方法上就能实现单操作级别的权限校验——哪怕一个HTTP请求里塞了多个操作,每个都会单独触发检查。

示例代码:

@Controller
public class BookController {

    @QueryMapping
    @PreAuthorize("hasAuthority('BOOK_READ')")
    public Book getBook(@Argument Long id) {
        // 业务逻辑
    }

    @MutationMapping
    @PreAuthorize("hasAuthority('BOOK_WRITE')")
    public Book createBook(@Argument BookInput input) {
        // 业务逻辑
    }
}

要启用这个功能,确保项目引入spring-boot-starter-graphql和spring-boot-starter-security依赖,然后配置Spring Security支持GraphQL:

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
            .oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt)
            // 开启GraphQL权限校验支持
            .graphql(graphql -> graphql.authorizeRequests(auth -> auth
                .anyRequest().authenticated()
            ));
        return http.build();
    }
}

方案2:自定义DataFetcher拦截器

如果需要完全自定义校验逻辑(比如自己搞注解规则),可以用Spring GraphQL的DataFetcherInterceptor——它专门用来拦截单个DataFetcher(也就是控制器里的每个query/mutation方法)的执行流程。

步骤如下:

  1. 定义自定义权限注解:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RequirePermission {
    String value(); // 传入权限标识,比如"BOOK_READ"
}
  1. 实现拦截器,在方法执行前检查注解:
@Component
public class PermissionInterceptor implements DataFetcherInterceptor {

    @Override
    public CompletionStage<Object> intercept(DataFetcherInvocation invocation) {
        // 获取当前执行的控制器方法
        Method targetMethod = getTargetMethod(invocation);
        if (targetMethod == null) {
            return invocation.proceed();
        }

        // 检查是否存在自定义权限注解
        if (targetMethod.isAnnotationPresent(RequirePermission.class)) {
            RequirePermission annotation = targetMethod.getAnnotation(RequirePermission.class);
            String requiredPerm = annotation.value();

            // 校验当前用户权限
            Authentication auth = SecurityContextHolder.getContext().getAuthentication();
            if (auth == null || !auth.getAuthorities().stream()
                    .anyMatch(a -> a.getAuthority().equals(requiredPerm))) {
                throw new AccessDeniedException("无权限执行此操作");
            }
        }

        // 继续执行原方法
        return invocation.proceed();
    }

    // 辅助方法:从invocation中解析出对应的控制器方法
    private Method getTargetMethod(DataFetcherInvocation invocation) {
        try {
            return invocation.getTarget().getClass().getMethod(
                    invocation.getDefinition().getName(),
                    invocation.getArguments().values().stream()
                            .map(Object::getClass)
                            .toArray(Class[]::new)
            );
        } catch (NoSuchMethodException e) {
            return null;
        }
    }
}
  1. 在控制器方法上使用自定义注解:
@Controller
public class BookController {

    @QueryMapping
    @RequirePermission("BOOK_READ")
    public Book getBook(@Argument Long id) {
        // 业务逻辑
    }
}

核心原理

Spring GraphQL里,每个query/mutation对应的控制器方法本质是一个DataFetcher,所以针对DataFetcher的拦截就是精准作用于单个GraphQL操作,和HTTP请求层面的拦截完全独立,正好满足你的需求。

内容的提问来源于stack exchange,提问作者Marsh

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 05:07:39