且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

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

更新时间:2022-04-21 16:04:56

我们使用.antMatchers("/graphql").permitAll()代替了.antMatchers("/graphql").permitAll(),然后删除了.httpBasic(),还删除了自定义的AuthenticationProvider.现在,安全配置如下所示:

Instead of .antMatchers("/graphql").authenticated() we used .antMatchers("/graphql").permitAll(), then we removed .httpBasic() and also removed the custom AuthenticationProvider. Now the security configs look like this:

@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模式:

Then we created a mutation for login that accepts the user's credentials and returns the session token. Here is the graphql schema:

login(credentials: CredentialsInputDto!): String

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

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

Basically the code we had in our custom AuthenticationProvider went into the service that is called by the login operation:

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便能够自动恢复上下文.

The key is that we prepared the session context with the authenticated user's authentication and then we save it (in redis) as a session attribute called "SPRING_SECURITY_CONTEXT". This is all what spring needs to be able to automatically restore the context when you make a request having the "x-auth-token" header set with the value of the session token obtained from the login operation.

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

Now also anonymous calls are allowed because of .antMatchers("/graphql").permitAll() and in the service layer, on public methods we can use annotations like this: @Preauthorize("isAnonymous() OR hasRole("USER")").