我在CORS上遇到了一个问题,我try 了everything个我可以在Stack Overflow上找到的东西,基本上是我在Google上找到的任何东西,但都没有运气.

因此,我在后端有用户身份验证,在前端有一个登录页面.我用Axios连接了登录页面,这样我就可以发出post请求并try 登录,但我不断出现"飞行前请求"之类的错误,所以我修复了这个问题,然后我开始出现"post 403禁止"错误.

看起来是这样的:

POST http://localhost:8080/api/v1/login/ 403 (Forbidden)

即使try 使用postman 登录也不起作用,所以显然有些地方出了问题.将在下面发布班级档案

在我的后端,我有一个名为WebSecurityConfig的类,它处理所有CORS内容:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsServiceImpl userDetailsService;

    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurerAdapter() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/**")
                        .allowedMethods("GET", "POST", "HEAD", "PUT", "DELETE", "OPTIONS");
            }
        };
    }

    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true);
        config.addAllowedOrigin("*");  // TODO: lock down before deploying
        config.addAllowedHeader("*");
        config.addExposedHeader(HttpHeaders.AUTHORIZATION);
        config.addAllowedMethod("*");
        source.registerCorsConfiguration("/**", config);
        return new CorsFilter(source);
    }


    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.headers().frameOptions().disable();
        http
                .cors()
                .and()
                .csrf().disable().authorizeRequests()
                .antMatchers("/").permitAll()
                .antMatchers("/h2/**").permitAll()
                .antMatchers(HttpMethod.POST, "/api/v1/login").permitAll()
                .anyRequest().authenticated()
                .and()
                // We filter the api/login requests
                .addFilterBefore(new JWTLoginFilter("/api/v1/login", authenticationManager()),
                        UsernamePasswordAuthenticationFilter.class);
        // And filter other requests to check the presence of JWT in header
        //.addFilterBefore(new JWTAuthenticationFilter(),
        //       UsernamePasswordAuthenticationFilter.class);
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // Create a default account
        auth.userDetailsService(userDetailsService);
//        auth.inMemoryAuthentication()
//                .withUser("admin")
//                .password("password")
//                .roles("ADMIN");
    }
}

在我们用VueJS编写的前端,使用Axios进行通话

<script>
    import { mapActions } from 'vuex';
    import { required, username, minLength } from 'vuelidate/lib/validators';

    export default {
        data() {
            return {
                form: {
                    username: '',
                    password: ''
                },
                e1: true,
                response: ''
            }
        },
        validations: {
            form: {
                username: {
                    required
                },
                password: {
                    required
                }
            }
        },
        methods: {
            ...mapActions({
                setToken: 'setToken',
                setUser: 'setUser'
            }),
            login() {
                this.response = '';
                let req = {
                    "username": this.form.username,
                    "password": this.form.password
                };

                this.$http.post('/api/v1/login/', req)
                .then(response => {
                    if (response.status === 200) {
                        this.setToken(response.data.token);
                        this.setUser(response.data.user);

                        this.$router.push('/dashboard');
                    } else {
                        this.response = response.data.error.message;
                    }
                }, error => {
                    console.log(error);
                    this.response = 'Unable to connect to server.';
                });
            }
        }
    }
</script>

因此,当我通过Chrome的工具(网络)进行调试时,我注意到选项请求如下所示:

OPTIONS request going through

以下是POST错误的图片:

POST Request Error

下面是另一个处理选项请求的类(WebSecurityConfig中引用的JWTLoginFilter):

public class JWTLoginFilter extends AbstractAuthenticationProcessingFilter {

    public JWTLoginFilter(String url, AuthenticationManager authManager) {
        super(new AntPathRequestMatcher(url));
        setAuthenticationManager(authManager);

    }

    @Override
    public Authentication attemptAuthentication(
            HttpServletRequest req, HttpServletResponse res)
            throws AuthenticationException, IOException, ServletException {
        AccountCredentials creds = new ObjectMapper()
                .readValue(req.getInputStream(), AccountCredentials.class);
        if (CorsUtils.isPreFlightRequest(req)) {
            res.setStatus(HttpServletResponse.SC_OK);
            return null;

        }
        return getAuthenticationManager().authenticate(
                new UsernamePasswordAuthenticationToken(
                        creds.getUsername(),
                        creds.getPassword(),
                        Collections.emptyList()

                )
        );
    }

    @Override
    protected void successfulAuthentication(
            HttpServletRequest req,
            HttpServletResponse res, FilterChain chain,
            Authentication auth) throws IOException, ServletException {
        TokenAuthenticationService
                .addAuthentication(res, auth.getName());
    }
}

推荐答案

配置Axios时,只需一次性指定标头即可:

import axios from "axios";

const CSRF_TOKEN = document.cookie.match(new RegExp(`XSRF-TOKEN=([^;]+)`))[1];
const instance = axios.create({
  headers: { "X-XSRF-TOKEN": CSRF_TOKEN }
});
export const AXIOS = instance;

然后(这里我假设您使用SpringBoot 2.0.0,而它也应该在SpringBoot 1.4.x以后的版本中工作)在Spring Boot应用程序中,您应该添加以下安全配置.

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            // CSRF Token
            .csrf()
                .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
           // you can chain other configs here
    }

}

这样,Spring将在响应中以cookie的形式返回令牌(我假设您先执行GET),然后在AXIOS配置文件中读取它.

Vue.js相关问答推荐

如何使用composition api v-model Select 框获取其他JSON 值?

保持页面重新加载之间的状态

更新 Shopware 管理 CMS 组件中的编辑器视图

两个div元素之间的vue2过渡

我可以在打印 HTML 页面时使用作用域 CSS 吗? (使用 Laravel 和 Vue.js)

VueJS:如何在组件数据属性中引用 this.$store

使用 Vue Js 运行 Jest 测试时出现语法错误:无法在模块外使用 import 语句

如何在 Laravel 中包含 Bootstrap-Vue

如何只查看数组中的一个对象?

Laravel Vue - 如何让 vue 在公共文件夹中查找图像

使用 azure devops 发布管道部署 Vue.js 应用程序

导入没有 .vue 扩展名的 *.vue 文件时出现以下错误?

如何在某些路由上隐藏全局组件(例如导航栏)?

Vuetify - 根据另一个 Select 选项过滤 Select 数据

触发子函数

如何异步验证 Vuetify 文本字段?

Vue组件未在laravel 5.3中使用Passport 显示

来自 Vue.js 的 ESLint 插件的消息中的LHS是什么意思?

使用 puppeteer 生成 PDF 而不保存

Vue v-model 不响应 BS4 单选按钮组