Spring + GraphQL - 可选授权

时间:2018-05-26 10:30:15

标签: spring spring-boot spring-security graphql graphql-java

我目前正在使用Spring Boot StarterGraphQL 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端点,那么即使我提供了有效的JWT,也不会发生任何授权,因此每个@PreAuthorize都会失败。 可能我的方法已经错了。如果是这种情况,请告诉我。

1 个答案:

答案 0 :(得分:0)

我使用两个安全配置解决了这个问题。一个用于我的REST api,它强制执行身份验证/授权。另一个具有可选的授权过滤器,仅在令牌存在时才使用该令牌。 现在唯一的缺点是默认情况下所有查询和变异都向公众开放,并且需要关闭<http://example/XYZ/saphieron/platforms/home/plants/2> 注释。