web-dev-qa-db-ja.com

graphqlを使用したSpring Bootでの認証

私はGraphQLで春のブートプロジェクトに取り組んでいます。私は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()に変更すると、「基本的なhttp認証」で認証しようとしても、カスタムAuthenticationProviderが呼び出されなくなります。

ありがとう!

これが私の設定です:

_@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();
    }

}
_
11
Roland

.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")")

5
Roland

permitAll()を使用する必要がある場合でも、AOPを使用してリゾルバーメソッドに適切なデフォルトを作成できます。

デフォルトで認証を要求するカスタムセキュリティアスペクトを作成できます。

セキュリティで保護されていないメソッドは、たとえば注釈を使用してマークすることができます。

詳細については、私のブログ投稿を参照してください: https://mi3o.com/spring-graphql-security

6
Michal Gebauer