Java 由于CORS,Spring安全注销不工作

Java 由于CORS,Spring安全注销不工作,java,spring,spring-security,axios,Java,Spring,Spring Security,Axios,技术:Spring Security、后端的Spring Boot以及前端的ReactJs和axios 我想要什么:在我的前端点击注销按钮时,我想注销用户。为此,我使用delete调用后端。然后我希望我的后端注销 我的问题:当我从我的前端调用Spring Security注销端点时,我收到以下消息: 加载失败http://localhost:8080/logout: 对飞行前请求的响应未通过访问控制检查:请求的资源上不存在“访问控制允许来源”标头。起源'http://localhost:8888

技术:Spring Security、后端的Spring Boot以及前端的ReactJs和axios

我想要什么:在我的前端点击
注销
按钮时,我想注销用户。为此,我使用
delete
调用后端。然后我希望我的后端注销

我的问题:当我从我的前端调用Spring Security
注销
端点时,我收到以下消息:
加载失败http://localhost:8080/logout: 对飞行前请求的响应未通过访问控制检查:请求的资源上不存在“访问控制允许来源”标头。起源'http://localhost:8888因此,不允许访问。响应的HTTP状态代码为403。
我确实理解出现此错误的原因-后端在localhost:8080上,前端在localhost:8888上。但我不理解的是,为什么我的配置不适用于注销,而在所有其他情况下(例如,调用spring security
login
endpoint或我的一些自定义endpoint)它工作得非常好

我如何从前端拨打电话

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};
    });
@Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurerAdapter() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/**").allowedOrigins("http://localhost:8888");
            }
        };
    }
从前端启用CORS

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};
    });
@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.");
    }
}

我检查了的源代码

如您所见,默认情况下,
Delete
方法是不允许的,因此您需要添加
Delete
方法

@Bean
public WebMvcConfigurer corsConfigurer() {
  return new WebMvcConfigurerAdapter() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/**")
                            .allowedOrigins("http://localhost:8888")
                            .addAllowedMethod(HttpMethod.DELETE);
            }
        };
    }

为什么要使用
删除/注销
?在我看来,这完全出乎意料,离最佳实践相去甚远。在/注销时没有可删除的资源。我建议
POST/logout
DELETE/session
。谢谢您的建议。我将使用
POST/logout
。这就是问题所在。多谢各位!