使用 graphql 在 spring 引导中进行身份验证
authentication in spring boot using graphql
我正在使用 GraphQL 开发一个 spring 引导项目。我正在使用 graphql-java-tools 和 graphql-spring-boot-starter。正如您在下面的 java 配置文件中看到的那样,我设法使用 spring 安全配置安全和 session 管理。
现在“/graphql”路径是安全的(只有在 http header 中发送“基本 http 身份验证”或 session 令牌(x-auth-token
)才能访问它的请求)。在任何 GraphQL 操作上使用“基本 http 身份验证”进行身份验证将启动一个新的 session 并在 header 中发回新的 session 令牌,并且该令牌可以进一步用于继续 session.
如何允许匿名用户访问某些 GraphQL queries/mutations 保持上述行为?
如果我将 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();
}
}
我们使用 .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();
}
}
然后我们为登录创建了一个突变,它接受用户的凭据和 returns session 令牌。这是 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();
}
关键是我们用经过身份验证的用户身份验证准备了 session 上下文,然后我们将其保存(在 redis 中)作为名为 "SPRING_SECURITY_CONTEXT" 的 session 属性.这就是 spring 需要能够在您发出请求时自动恢复上下文的全部内容 "x-auth-token" header 设置了从获得的 session 令牌的值登录操作。
由于 .antMatchers("/graphql").permitAll()
,现在也允许匿名调用,并且在服务层中,在 public 方法上,我们可以使用这样的注释:@Preauthorize("isAnonymous()
或 hasRole("USER")")
。
即使您需要使用 permitAll()
,您仍然可以使用 AOP 为您的解析器方法创建合理的默认值。
您可以创建默认需要身份验证的自定义安全方面。
不安全的方法可能会被标记,例如使用注释。
详见我的博客post:https://michalgebauer.github.io/spring-graphql-security
我正在使用 GraphQL 开发一个 spring 引导项目。我正在使用 graphql-java-tools 和 graphql-spring-boot-starter。正如您在下面的 java 配置文件中看到的那样,我设法使用 spring 安全配置安全和 session 管理。
现在“/graphql”路径是安全的(只有在 http header 中发送“基本 http 身份验证”或 session 令牌(x-auth-token
)才能访问它的请求)。在任何 GraphQL 操作上使用“基本 http 身份验证”进行身份验证将启动一个新的 session 并在 header 中发回新的 session 令牌,并且该令牌可以进一步用于继续 session.
如何允许匿名用户访问某些 GraphQL queries/mutations 保持上述行为?
如果我将 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();
}
}
我们使用 .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();
}
}
然后我们为登录创建了一个突变,它接受用户的凭据和 returns session 令牌。这是 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();
}
关键是我们用经过身份验证的用户身份验证准备了 session 上下文,然后我们将其保存(在 redis 中)作为名为 "SPRING_SECURITY_CONTEXT" 的 session 属性.这就是 spring 需要能够在您发出请求时自动恢复上下文的全部内容 "x-auth-token" header 设置了从获得的 session 令牌的值登录操作。
由于 .antMatchers("/graphql").permitAll()
,现在也允许匿名调用,并且在服务层中,在 public 方法上,我们可以使用这样的注释:@Preauthorize("isAnonymous()
或 hasRole("USER")")
。
即使您需要使用 permitAll()
,您仍然可以使用 AOP 为您的解析器方法创建合理的默认值。
您可以创建默认需要身份验证的自定义安全方面。
不安全的方法可能会被标记,例如使用注释。
详见我的博客post:https://michalgebauer.github.io/spring-graphql-security