更新时间: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")")
.