Spring + GraphQL - 可选授权

Posted

技术标签:

【中文标题】Spring + GraphQL - 可选授权【英文标题】:Spring + GraphQL - optional authorization 【发布时间】:2018-11-05 14:18:21 【问题描述】:

我目前正在使用 Spring Boot Starter 和 GraphQL Java Tools 在我的 Spring 应用程序中使用 GraphQL。只要我授权了graphql端点,它就可以与我的授权过滤器一起很好地工作。现在我想向公众开放某些突变或查询(因此不需要授权),这就是我绊倒的地方。如何打开 graphql 端点,但仍然能够使用 Spring 安全性的 @PreAuthorize 注释进行方法级授权?换句话说:是否可以在端点上进行“可选”授权?

这是我的配置:

@Override
protected void configure(HttpSecurity http) throws Exception 
    log.debug("configureHttpSecurity");

    // Only authorize the request if it is NOT in the permitAllEndpoints AND matches API_ROOT_URL OR
    // MESSAGING_ROOT_URL
    List<RequestMatcher> requestMatchers = new ArrayList<>();
    requestMatchers.add(new SkipPathRequestMatcher(permitAllEndpointList, API_ROOT_URL));
    requestMatchers.add(new AntPathRequestMatcher(MESSAGING_ROOT_URL));
    OrRequestMatcher apiMatcher = new OrRequestMatcher(requestMatchers);

    http.csrf().disable()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and()
                .authorizeRequests()
                .antMatchers(permitAllEndpointList.toArray(new String[0]))
                .permitAll()
            .and()
                .authorizeRequests()
                .antMatchers(API_ROOT_URL, MESSAGING_ROOT_URL)
                .authenticated()
            .and()
                .addFilterBefore(new CustomCorsFilter(),
                        UsernamePasswordAuthenticationFilter.class)
                .addFilterBefore(new AuthenticationFilter(authenticationManager()),
                        UsernamePasswordAuthenticationFilter.class)
                .addFilterBefore(new AuthorizationFilter(apiMatcher),
                        UsernamePasswordAuthenticationFilter.class);

apiMatcher 用于打开某些 REST 端点。 这是我的AuthorizationFilter

@Override
public Authentication attemptAuthentication(HttpServletRequest httpServletRequest,
                                            HttpServletResponse httpServletResponse)
        throws AuthenticationException, IOException, ServletException 
    try 
        String authorization = httpServletRequest.getHeader("Authorization");
        if (authorization != null && authorization.startsWith("Bearer ")) 
            return getAuthentication(authorization.replace("Bearer ", ""));
        
     catch (ExecutionException e) 
        httpServletResponse.sendError(HttpServletResponse.SC_FORBIDDEN,"The provided token was either not valid or is already expired!");
        return null;
     catch (IOException | InterruptedException e) 
        httpServletResponse.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,"There was a problem verifying the supplied token!");
        return null;
    
    httpServletResponse.sendError(HttpServletResponse.SC_FORBIDDEN, "Unauthorized");
    return null;

如果我不在attemptAuthentication 末尾发送错误,我将能够访问不应打开的 REST 端点。此外,如果我只允许 GraphQL 端点,则不会发生授权,因此每个 @PreAuthorize 都会失败,即使我提供了有效的 JWT。 可能是我的处理方法已经是错误的了。如果是这种情况,请告诉我。

【问题讨论】:

【参考方案1】:

我通过使用两个安全配置解决了这个问题。一个用于我的 REST api,它已强制执行身份验证/授权。另一个有一个可选的授权过滤器,它只使用存在的令牌。 现在唯一的缺点是所有查询和变异默认对公众开放,需要关闭@PreAuthorize注解。

【讨论】:

以上是关于Spring + GraphQL - 可选授权的主要内容,如果未能解决你的问题,请参考以下文章

面对极度复杂的前后端业务场景,使用 GraphQL 正确的姿势

使用 @PreAuthorize 的 GraphQL 和 Spring Security?

graphql node api:如何将字段定义为可选?

如何在 GraphQL 中使用可选参数实现突变?

GraphQL:使用多个可选参数创建请求

可选字段图像和 'childImageSharp' 为 null |盖茨比、GraphQL 和 YAML