文章目录

  • 问题描述
  • 开发环境
  • 解决方案
  • 前端部分
  • 后端部分
  • 部分解决问题
  • 全局支持跨域
  • 效果图
  • 部分问题
  • 被识别为跨站攻击
  • 解决方案
  • 普罗大众式
  • 突发奇想式
  • 绝对离谱式
  • 相对靠谱(推荐)
  • 最终选取方案


问题描述

请求地址不同所引发的报错问题

提示信息:blocked by CORS policy: No ‘Access-Control-Allow-Origin‘ header is present on the requested resource

axios cross axios cross policy_axios cross

开发环境

前端:Vue + html三件套 + Axios(用于发送异步请求)
后端:javax.servlet + Mybatis

解决方案

前端部分

在axios请求中添加withCredentials: true 使得axios允许携带cookie

例子:

axios({
    method:'post',
    url:"http://127.0.0.1/user/login",
    data:{"email": "2776483968@qq.com","password": "*"},
    withCredentials: true // 允许携带cookie
    }).then(resp=>{
    console.log(resp);
})
axios({
    method:'get',
    url:"http://127.0.0.1/user",
    withCredentials:true // 允许携带cookie
    }).then(resp=>{
    console.log(resp);
})

后端部分

有两种解决方式,一种是部分解决跨域问题,另一种是全局支持跨域问题
个人感觉如果全局支持会导致网站的安全性下降,谨慎使用

部分解决问题

在服务端添加响应头:
response.setHeader("Access-Control-Allow-Origin","*");

第二个参数是 * 表示允许任何域名跨域访问

response.setHeader("Access-Control-Allow-Origin","http:localhost:8080");

第二个参数是特定域名则只有它可以访问

全局支持跨域

写一个Filter过滤器过滤地址\*就可以全局过滤了

具体代码如下

package cn.imerji.web.filter;

import javax.servlet.*;
import javax.servlet.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebFilter(filterName = "Filter_CrossOrigin",urlPatterns = "/*")
public class Filter_CrossOrigin implements Filter {
    public void init(FilterConfig config) throws ServletException {
    }

    public void destroy() {
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
        HttpServletRequest request1 = (HttpServletRequest) request;
        HttpServletResponse response1 = (HttpServletResponse) response;
        response1.setHeader("Access-Control-Allow-Origin", request1.getHeader("origin"));
        response1.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE");
        response1.setHeader("Access-Control-Max-Age", "3600");
        response1.setHeader("Access-Control-Allow-Headers", "x-requested-with, Content-Type");
        response1.setHeader("Access-Control-Allow-Credentials", "true");
        chain.doFilter(request1, response1);
    }
}

效果图

axios cross axios cross policy_axios cross_02


axios cross axios cross policy_java_03


axios cross axios cross policy_servlet_04


但是如果域名不同会引发下述问题

部分问题

被识别为跨站攻击

通过谷歌浏览器的报错SameSite属性了解到,可能发送请求cookie时被认为是跨站攻击
Cookie 的SameSite属性用来限制第三方 Cookie,从而减少安全风险。
最好的办法,不要搞这样的开发

解决方案

普罗大众式

首先要将SameSite属性设置为None,其次要使用https安全链接。

突发奇想式

两个网站使用同一个一级域名,
比如a网站域名为: a.xxxx.com
b网站域名为: b.xxxx.com

绝对离谱式

使用Chrome(谷歌)浏览器打开
chrome://flags/#site-isolation-trial-opt-outSameSite by default cookies设置为disabled,重启浏览器即可正常使用
但是好像不是每个人都可以设置自己的浏览器,所以绝对离谱
虽然离谱但是有效
事件起因

相对靠谱(推荐)

直接把session按照SameSite的需求重写一遍set

response.addHeader("Set-Cookie", String.format("%s; %s", String.format("JSESSIONID=%s; Max-Age=%s; Path=/;%s HttpOnly", request1.getSession().getId(), 3600, " Secure;"), "SameSite=None"));

我选择的是用过滤器每一次请求都设置一次Session,如果正式开发我肯定不会这么考虑(但是问题解决了)

最终选取方案

前端设置好withCredentials 后端采用了普罗大众式
写好过滤器Filter,并且重新写好set-Cookie的格式