一尘不染

使用graphql在Spring Boot中进行身份验证

spring-boot

我正在使用GraphQL进行Spring Boot项目。我正在使用graphql-java-tools和graphql-spring-boot-
starter。正如您在下面的Java配置文件中看到的那样,我设法通过Spring Security配置了安全性和会话管理。

现在,“ / graphql”路径已得到保护(只能x-auth- token在请求的HTTP标头中发送“基本http身份验证”或会话令牌()才能访问它)。在任何GraphQL操作上使用“基本http身份验证”进行身份验证将启动一个新会话,并在标头中发送回新的会话令牌,并且可以将该令牌进一步用于继续该会话。

如何授予匿名用户访问某些GraphQL查询/突变的权限,以保持上述行为?

如果为了允许匿名访问而更改antMatchers("/graphql").authenticated()antMatchers("/graphql").permitAll(),则AuthenticationProvider即使尝试使用“基本http身份验证”进行身份验证,也不再调用我的自定义。

谢谢!

这是我的配置:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private AuthenticationProvider authenticationProvider;

    @Override
    public void configure(AuthenticationManagerBuilder authenticationManagerBuilder) {
        authenticationManagerBuilder.authenticationProvider(authenticationProvider);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .csrf().disable()
            .authorizeRequests()
            .antMatchers("/graphql").authenticated()
            .and()
            .requestCache()
            .requestCache(new NullRequestCache())
            .and()
            .httpBasic()
            .and()
            .headers()
            .frameOptions().sameOrigin() // needed for H2 web console
            .and()
            .sessionManagement()
            .maximumSessions(1)
            .maxSessionsPreventsLogin(true)
            .sessionRegistry(sessionRegistry());
    }

    @Bean
    public SessionRegistry sessionRegistry() {
        return new SessionRegistryImpl();
    }

    @Bean
    public HttpSessionEventPublisher httpSessionEventPublisher() {
        return new HttpSessionEventPublisher();
    }
}



@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 180)
public class HttpSessionConfig {

    @Bean
    public HttpSessionStrategy httpSessionStrategy() {
        return new HeaderHttpSessionStrategy();
    }

}

阅读 1103

收藏
2020-05-30

共1个答案

一尘不染

而不是.antMatchers("/graphql").authenticated()我们使用了.antMatchers("/graphql").permitAll(),然后我们删除了,.httpBasic()并且还删除了自定义AuthenticationProvider。现在,安全性配置如下所示:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .csrf().disable()
            .authorizeRequests()
            .antMatchers("/graphql").permitAll()
            .and()
            .requestCache()
            .requestCache(new NullRequestCache())
            .and()
            .headers()
            .frameOptions().sameOrigin() // needed for H2 web console
            .and()
            .sessionManagement()
            .maximumSessions(1)
            .maxSessionsPreventsLogin(true)
            .sessionRegistry(sessionRegistry());
    }

    @Bean
    public SessionRegistry sessionRegistry() {
        return new SessionRegistryImpl();
    }

    @Bean
    public HttpSessionEventPublisher httpSessionEventPublisher() {
        return new HttpSessionEventPublisher();
    }
}

然后,我们为登录创建了一个变异,该变异接受用户的凭据并返回会话令牌。这是graphql模式:

login(credentials: CredentialsInputDto!): String

input CredentialsInputDto {
    username: String!
    password: String!
}

基本上,我们在自定义AuthenticationProvider中拥有的代码进入了登录操作所调用的服务:

public String login(CredentialsInputDto credentials) {
    String username = credentials.getUsername();
    String password = credentials.getPassword();

    UserDetails userDetails = userDetailsService.loadUserByUsername(username);

    ... credential checks and third party authentication ...

    Authentication authentication = new UsernamePasswordAuthenticationToken(username, password, userDetails.getAuthorities());
    SecurityContextHolder.getContext().setAuthentication(authentication);
    httpSession.setAttribute("SPRING_SECURITY_CONTEXT", SecurityContextHolder.getContext());
    return httpSession.getId();
}

关键是我们准备了具有经过身份验证的用户的身份验证的会话上下文,然后将其保存(以redis格式)作为称为“
SPRING_SECURITY_CONTEXT”的会话属性。当您发出一个请求,该请求设置了“ x-auth-
token”标头并设置了从登录操作获取的会话令牌的值时,spring便能够自动恢复上下文。

现在,由于.antMatchers("/graphql").permitAll()在服务层中并且在服务层中,也允许匿名调用,在公共方法上,我们可以使用如下注释:@Preauthorize("isAnonymous()OR
hasRole("USER")")

2020-05-30