由于CORS,Spring安全注销无法正常工作

时间:2017-10-22 10:38:22

标签: java spring spring-security axios

技术: 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.");
    }
}

1 个答案:

答案 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);
            }
        };
    }