spring security+vue+axios,为什么通过spring security认证成功之后,访问再次发送请求访问受保护资源,浏览器没有自动携带set-cookie?

spring security+vue+axios,为什么通过spring security认证成功之后,访问再次发送请求访问受保护资源,浏览器没有自动携带set-cookie?
这是spring security配置代码:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter{
    private final MyUserDetailService myUserDetailService;
    public SecurityConfig(MyUserDetailService myUserDetailService) {
        this.myUserDetailService = myUserDetailService;
    }
    @Override
    protected void configure(AuthenticationManagerBuilder auth)throws Exception{
        auth.userDetailsService(myUserDetailService);
    }
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception{
        return super.authenticationManagerBean();
    }
    @Bean
    public LoginFilter loginFilter() throws Exception {
        LoginFilter loginFilter = new LoginFilter();
        loginFilter.setFilterProcessesUrl("/api/doLogin");//指定认证的url
        //指定用户名和密码的key
        loginFilter.setUsernameParameter("uname");
        loginFilter.setPasswordParameter("passwd");
        loginFilter.setAuthenticationManager(authenticationManagerBean());
        loginFilter.setAuthenticationSuccessHandler((request, response, authentication) -> {
            System.out.println(SecurityContextHolder.getContext().getAuthentication());
            HashMap<Object, Object> hashMap = new HashMap<>();
            hashMap.put("token", "646031654");
            hashMap.put("userinfo", authentication.getPrincipal());
            AjaxResult ajaxResult = new AjaxResult();
            ajaxResult.setResultObj(hashMap);
            String valueAsString = new ObjectMapper().writeValueAsString(ajaxResult);
            response.setContentType("application/json;charset=UTF-8");
            response.addHeader("Access-Control-Allow-Origin", response.getHeader("Origin"));
            response.setHeader("Access-Control-Allow-Credentials", "true");
            response.setHeader("Set-Cookie", "SameSite=None");
            response.getWriter().println(valueAsString);
        });//认证成功处理
        loginFilter.setAuthenticationFailureHandler((request, response, exception) -> {
            HashMap<Object, Object> hashMap = new HashMap<>();
            hashMap.put("msg", "登陆失败"+exception.getMessage());
            response.setContentType("application/json;charset=UTF-8");
            response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
            String valueAsString = new ObjectMapper().writeValueAsString(hashMap);
            response.getWriter().println(valueAsString);
        });//认证失败处理
        return loginFilter;
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .requestMatchers(CorsUtils::isPreFlightRequest).permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .and()
                .exceptionHandling()//认证异常处理
                .authenticationEntryPoint((request, response, authException) -> {
                    response.setContentType("application/json;charset=UTF-8");
                    response.setStatus(HttpStatus.UNAUTHORIZED.value());
                    response.getWriter().println(new AjaxResult().setMessage("请认证"));
                })
                .and()
                .logout()
                .logoutUrl("/logout")
                .logoutSuccessHandler((request, response, authentication) -> {
                    HashMap<Object, Object> hashMap = new HashMap<>();
                    hashMap.put("msg", "操作成功");
                    hashMap.put("status", "200");
                    hashMap.put("authentication",authentication.getPrincipal());
                    response.setContentType("application/json;charset=UTF-8");
                    String valueAsString = new ObjectMapper().writeValueAsString(hashMap);
                    response.getWriter().println(valueAsString);
                })
                .and()
                .cors()//跨域处理方案
                //.configurationSource(configurationSource())
                .and()
                .csrf().disable()
                .headers()
                .httpStrictTransportSecurity().disable()
                .referrerPolicy(Customizer.withDefaults())
                .contentSecurityPolicy("script-src 'self'");
        /**
         * At:用某个filter替换过滤器链的某个filter
         * Before:放在滤器链的某个filter之前
         * After:放在滤器链的某个filter之后
         */
        http.addFilterAt(loginFilter(), UsernamePasswordAuthenticationFilter.class);
    }
    @Bean
    CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        //corsConfiguration.setAllowedOriginPatterns(Arrays.asList("http://.*"));
        //corsConfiguration.setAllowCredentials(true);
        corsConfiguration.addAllowedOrigin("*");
        corsConfiguration.addAllowedHeader("*");
        corsConfiguration.addAllowedMethod("*");
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", corsConfiguration);
        return source;
    }

}

这是axios代码:

import axios from "axios";

const http = axios.create({
    //通用请求地址前缀
    baseURL:'http://127.0.0.1:8011',
    //超时时间
    timeout:10000,
    withCredentials:true,
    crossDomain: true
})

前端api

import http from "@/utils/request";

//用户登录
export const userLogin =(data) => {
    return http.post('/api/doLogin', data)
}

登录成功之后浏览器响应接口:

img


再次发送请求浏览器的请求体:

img

【以下回答由 GPT 生成】

问题的根本原因是浏览器在进行跨域请求时,需要服务器在响应中设置Access-Control-Allow-Credentials为true,并且设置set-cookie时,还需要设置SameSite属性为None。

由于您使用的是Spring Security进行认证,所以可以通过添加一个CorsFilter来解决这个问题。下面是一个简单的示例代码:

@Configuration
public class CorsConfig {

    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.setAllowCredentials(true);
        corsConfiguration.addAllowedOrigin("*");
        corsConfiguration.addAllowedHeader("*");
        corsConfiguration.addAllowedMethod("*");
        corsConfiguration.addExposedHeader("Set-Cookie"); // 添加ExposedHeader,将Set-Cookie暴露给前端
        source.registerCorsConfiguration("/**", corsConfiguration);
        return new CorsFilter(source);
    }

}

请将上述代码添加到您的Spring Boot项目中,并且确保它被正确加载到应用程序中。

此外,请确保您的浏览器支持SameSite属性的设置,因为不是所有的浏览器都支持该属性。 希望这可以解决您的问题。如果您还有其他问题,请随时向我询问。


如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^