技术: Spring Security,后端的Spring Boot以及前端的ReactJs和axios。
我想拥有的内容:点击我的前端的logout
按钮时,我想要注销用户。为此,我使用delete
拨打后端电话。然后我希望我的后端退出。
我的问题:当我从前端调用Spring Security logout
端点时,收到以下消息:
Failed to load http://localhost:8080/logout: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8888' is therefore not allowed access. The response had HTTP status code 403.
我明白为什么会出现这个错误 - 后端在localhost:8080上,前端在localhost:8888上。但是我不了解我的配置不适用于注销的原因,而它适用于所有其他情况(例如调用spring security login
端点或我的一些自定义端点。)
我如何从前端发出电话
const endpoint = 'logout';
return axios.delete(
'http://localhost:8080/' + `${endpoint}`,
{withCredentials: true}
)
.then(response => {
let resp = {
httpCode: response.status,
data: response.data
};
return {response: resp};
})
.catch(error => {
let err = {
httpStatusCode: error.response.status,
message: `Error calling endpoint ${endpoint}`
};
return {error: err};
});
从前端启用CORS
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("http://localhost:8888");
}
};
}
SecurityConfig.java - 在这里您可能会注意到某些部分已被评论 - 它们是我尝试的其他解决方案,但它们没有用。
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableWebSecurity
@EnableJpaRepositories(basePackageClasses = UsersRepository.class)
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private CustomUserDetailsService userDetailsService;
@Autowired
private RESTAuthenticationEntryPoint restAuthenticationEntryPoint;
@Autowired
private RESTAuthenticationSuccessHandler restAuthenticationSuccessHandler;
@Autowired
private RESTAuthenticationFailureHandler restAuthenticationFailureHandler;
@Bean
public CustomLogoutHandler customLogoutHandler(){
return new CustomLogoutHandler();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService)
.passwordEncoder(getPasswordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.cors()
.and()
.csrf().disable()
.authorizeRequests()
.antMatchers("**/anna/**").authenticated()
.anyRequest().permitAll()
.and()
.logout()
.addLogoutHandler(customLogoutHandler())
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"));
http.exceptionHandling().authenticationEntryPoint(restAuthenticationEntryPoint);
http.formLogin().successHandler(restAuthenticationSuccessHandler);
http.formLogin().failureHandler(restAuthenticationFailureHandler);
// http
// .logout()
// .logoutUrl("/logout")
// .addLogoutHandler(new CustomLogoutHandler())
// .invalidateHttpSession(true);
// http
// .cors()
// .and()
// .csrf().disable()
// .logout()
// .logoutRequestMatcher(new AntPathRequestMatcher("/logout"));
}
private PasswordEncoder getPasswordEncoder() {
return new PasswordEncoder() {
@Override
public String encode(CharSequence charSequence) {
return charSequence.toString();
}
@Override
public boolean matches(CharSequence charSequence, String s) {
return true;
}
};
}
}
CustomLogoutHandler.java 我在这里通过设置标题阅读了解决方案。我认为这是不好的做法,并且不愿意这样做,但基本上我很高兴看到日志正常工作。目前它没有记录任何内容,所以我猜它没有在注销时调用。
//@Slf4j
public class CustomLogoutHandler implements LogoutHandler{
@Override
public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication){
response.setHeader("Access-Control-Allow-Origin", "*");
System.out.println("TodosLogoutHandler logging you out of the back-end app.");
}
}
答案 0 :(得分:1)
我检查了CorsRegistration
的源代码,
public CorsConfiguration applyPermitDefaultValues() {
[...]
if (this.allowedMethods == null) {
this.setAllowedMethods(Arrays.asList(
HttpMethod.GET.name(), HttpMethod.HEAD.name(), HttpMethod.POST.name()));
}
[...]
return this;
}
正如您所见,Delete
方法默认为 NOT ALLOWED ,因此您需要添加delete
方法。
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:8888")
.addAllowedMethod(HttpMethod.DELETE);
}
};
}