首页 文章

使用graphql在spring boot中进行身份验证

提问于
浏览
6

我正在使用graphql开发一个spring boot项目 . 我正在使用graphql-java-tools和graphql-spring-boot-starter . 我设法使用spring安全性配置安全性和会话管理,如下面的java配置文件中所示 .

现在“/ graphql”路径是安全的(只能在请求的http头中发送“基本http身份验证”或会话令牌(x-auth-token)) . 在任何graphql操作上使用“基本http身份验证”进行身份验证将启动新会话并在标头中发回新会话令牌,并且可以进一步使用该令牌继续该会话 .

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

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

}

2 回答

  • 1

    我们使用.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()OR hasRole(”USER“) “) .

  • 3

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

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

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

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

相关问题