使用graphql在弹簧启动中进行身份验证

问题描述 投票:9回答:2

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

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

如何让匿名用户访问一些保留上述行为的graphql查询/突变?

如果我将antMatchers(“ / graphql”)。authenticated()更改为antMatchers(“ / graphql”)。permitAll()以允许匿名访问,那么即使我尝试通过auth进行身份验证,也不会再调用我的自定义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();
}

}
authentication spring-boot spring-security graphql graphql-java
2个回答
6
投票

即使您需要使用permitAll(),您仍然可以使用AOP为解析器方法创建合理的默认值。

您可以创建默认情况下需要身份验证的自定义安全性方面。

例如,可以使用注释标记不安全的方法。

有关详细信息,请参见我的博客文章:https://mi3o.com/spring-graphql-security


5
投票

我们使用.antMatchers(“ / graphql”)。permitAll()代替.antMatchers(“ / graphql”)。authenticated(),然后删除了.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()hasRole("USER")")

© www.soinside.com 2019 - 2024. All rights reserved.