文章目录

  • 前言
  • 1.跨域问题
    • 第一步,安装cors的扩展包
    • 第二步,导入应用
    • 第三步,插入中间件
    • 第四步,允许发送cookie
    • 第五步,设置白名单:
    • 第六步,设置允许的请求方法
    • 第七步,设置允许的其请求头
    • 第八步,测试
    • UPDATE:20210516 浏览器无法获取cookie问题
  • 2.CSRF问题和Cookie
    • 第一步,VUE的main.ts设置
    • 第二步,通过get请求先获取csrftoken
    • 第三步,请求中带上CSRFTOKEN
    • 更新:为什么请求要用URLSearchParams而不能直接用类
    • 获取Cookie的公共函数
  • 结语

前言

不行,我必须要总结一下,搞了两天,都在处理跨域的问题。
看到尤大的那句直接学VUE3就好,开始了VUE3+TS的刨坑之路,只能说不懂英语的程序员实在是太吃亏了,中文世界的VUE3资料十分零散,好难推进。

一来是就遇到以下三个问题:
1.跨域问题
2.csrf问题
3.cookie问题
问题本质上是为了完成Django的CSRF验证,但是三个问题互相纠缠非常麻烦。

1.跨域问题

由于是前后端分离的测试项目,目前还不知道最后部署是什么样的,所以我的Django项目开了3000的端口,而Vue这边的测试端口用的是8080,这样就触发了我们的大坑,跨域问题。
跨域问题的整体解决思路可以查看下面这个大大的文章:
https://juejin.cn/post/6844903536442998791
解决方法是使用CROS来处理相关问题,具体原理学习阮老师的文章(强烈建议通读这个文章):
http://www.ruanyifeng.com/blog/2016/04/cors.html
但是他没有给具体的解决方法,基本思路是通过修改Django部分的设置来处理,我操作起来大概是几个部分

第一步,安装cors的扩展包

python -m pip install django-cors-headers

第二步,导入应用

# settings.py
INSTALLED_APPS = [...# 处理跨域'corsheaders',
]

第三步,插入中间件

# settings.py
MIDDLEWARE = ['corsheaders.middleware.CorsMiddleware','django.middleware.clickjacking.XFrameOptionsMiddleware',
]

第四步,允许发送cookie

# settings.py
CORS_ALLOW_CREDENTIALS = True

第五步,设置白名单:

# settings.py
# CORS_ORIGIN_ALLOW_ALL = True
CORS_ORIGIN_WHITELIST =('http://127.0.0.1:8080','http://localhost:8080',
)

阮老师的文章里面有提到:

如果要发送Cookie,Access-Control-Allow-Origin就不能设为星号

但是经过我的测试,他这里的设置为CORS_ORIGIN_ALLOW_ALL 的情况下依旧可以获取Cookie不知道具体原因是什么,但是从安全角度出发,还是设置白名单比较安全。
值得注意的是,这里就算你设置了白名单可能还有一些问题会到会导致你无法取到Cookie,具体请看后面Cookie问题的那一节。

第六步,设置允许的请求方法

# settings.py
CORS_ALLOW_METHODS = ('DELETE','GET','OPTIONS','PATCH','POST','PUT','VIEW',
)

第七步,设置允许的其请求头

# settings.py
CORS_ALLOW_HEADERS = (# '*',该通配符无效'XMLHttpRequest','X_FILENAME','accept-encoding','authorization','content-type','dnt','origin','user-agent','x-csrftoken','x-requested-with','Pragma',
)

在这一步我卡了很久,一开始我这里是设置的星号*,以为是通配符。结果这个*并不能通配,比如后面的x-csrftoken就无法识别我的CSRF的KEY,导致我一直报错,后来是把星号去掉换成各个具体的头名名单才能通过。

Access to XMLHttpRequest at 'http://127.0.0.1:3000/login_action/' from origin 'http://127.0.0.1:8080' has been blocked by CORS policy: Request header field x-csrftoken is not allowed by Access-Control-Allow-Headers in preflight response.

第八步,测试

后端设置好后就可以通过POSTMAN来测试一下接口能不能使用,注意这里请用GET接口来做测试,因为GET接口是不用监测CSRF的,能正常返回的话我们可以看一下cookie这个返回值,里面应该会有我们的csrftoken,接下来就要搞这个。。。

UPDATE:20210516 浏览器无法获取cookie问题

我最近测试发现我cookie可能是用了之前测试的获取到的cookie,不太懂为什么,通过postman我们可以看到后台其实已经有返回csrftoken的cookie了。但是浏览器就是没办法收到,更过分的是我设置了一个测试的cookie,自己设置的这个识别出来了,但是csrftoken没办法识别。。。

POSTMAN截图如下:
chrome看到的cookie竟然是这样的:

我的scrftoken被你吞了???
不知道啥问题,咱么只能临时解决一下,希望如果有看到这个帖子的大大知道为什么可以指导我一下。
只能通过自己重新塞一个csrftoken来解决这个问题了。无语。。

res = HttpResponse(json.dumps(ret_dict, ensure_ascii=False), content_type="application/json")
res.set_cookie('csrftoken', get_token(request))
return res

现在就可以拿到了

2.CSRF问题和Cookie

CSRF和Cookie太紧密了,我就和在一点说了。
CSRF问题大家用过django的应该非常熟悉了,如果是Django自带的模板我们可以直接将数据渲染在模板里面,然后提交表单的时候带在参数里面就可以了。而在跨域的VUE上这事变得异常痛苦。
总的来说,你需要先通过一次GET请求获得附带在Cookie里面的CSRFTOKEN。然后再通过在POST请求中带上这个TOKEN来通过Django的CSRF认证。

第一步,VUE的main.ts设置

首先你要解决第一大点中的跨域问题,解决了并通过GET测试看到Cookie后再继续。
接下来你需要在main.ts中做好相应的配置保证获取到服务器的Cookie。

//main.ts
import axios from "axios";
//axios.defaults.baseURL = 'http://127.0.0.1:3000'
//这两个值好像默认就是这样了,所以不重要,重点是最后一个设置
axios.defaults.xsrfCookieName = 'csrfmiddlewaretoken'
axios.defaults.xsrfHeaderName = 'X-XSRF-TOKEN'
//重点!!!设置请求获取cookie
axios.defaults.withCredentials = true

如果我们没有做这个设置的话

withCredentials = true

就算后台允许发送cookie,还是不会收到cookie具体原理可以看阮老师的文章。

第二步,通过get请求先获取csrftoken

CSRF跨域是不会自动生成csrftoken的(深坑,之前POST后端报错csrf not set 就是这个原因)
post请求前必须先get一次产生token
from:https://www.cnblogs.com/linxizhifeng/p/8995077.html

如上所述,你需要先通过一次get操作来读取cookie里面的CSRF-KEY

axios.get('/login_action/',{withCredentials: true}).then((response) => {console.log(response)axios.defaults.headers['X-CSRFToken'] = getCsfrKey()})

这里我遇到一个坑:
cookie的同源问题
如果你有看我前面的那个测试你就能看出来Django返回的scrftoken是附在Cookie里面的,我们需要操作Cookie去取。但是一开始设置完我死活看不到Cookie,可是在前面POSTMAN测试里我们是可以看到Cookie的。
通过在console里面输入:

javascript:alert(document.cookie)

结果依旧是空,问题出在哪里呢?
其实是Cookie保存的同源策略的问题。
在VUE编译完后有两个地址可以点,我习惯去访问那个localhost的地址,如下图。

出现问题的原因如下图,简单来说,你的源地址要和你访问的这个地址同源。
从我的例子来说,我用
localhost -> 127.0.0.1
就不行,要用
127.0.0.1 -> 127.0.0.1
就可以了,因为服务器看你不会是一个叫做localhost的地址,而是127的具体地址,所以你本身的地址也要和127的相同,不然就没办法保存Cookie。
from:https://segmentfault.com/q/1010000009287272

第三步,请求中带上CSRFTOKEN

取到CSRF的KEY后我们有三种方式发送给后台:
1.直接在axios里面全局设置

axios.defaults.headers['X-CSRFToken'] = getCsfrKey()

2.在请求的头里面设置

axios.post('/login_action/',params,{headers:{"X-CSRFToken": getCsfrKey()}}).then((response) => {console.log(response.data)})

3.在参数里面设置

      let params = new URLSearchParams();params.append('user_name',formState.userName)params.append('pwd',formState.password)  params.append('csrfmiddlewaretoken',getCsfrKey())

我觉得还是第一种方便一点,一打开网页就可以先去获取key获取完后直接塞进axios里面,后面就都不用管了,多舒服。

这里也遇到一个坑,卡了很久。
就是跨域问题中的第七步中的允许头的问题。
问题的现象是,把带着CSRFTOKEN的POST请求上报服务器之后,Django的输出台看到的请求一直是OPTION,而不是我用的POST。
这个问题的根本就是由于跨域请求的时候,浏览器需要通过OPTION来和服务器确认自己到底能不能访问,确认过后才会发送我们的POST请求。由于后台设置的问题,一直我们请求头中的X-CSRFToken一直没办法被后台接收,导致OPTION的返回请求中没有带上我们需要的头,虽然返回code是200,但是浏览器遗留以为我们被后台跨域拒绝了,一直给我报跨域的错,后面把*给改成具体的头就OK了。

更新:为什么请求要用URLSearchParams而不能直接用类

主要是contenttype的问题
如果你用类直接提交,那你的Content-Type是json,有些后端没办法直接获取,需要后端手动处理。
而axios需要使用URLSearchParams,将Content-Type变为x-www-form-urlencoded,表单数据一般后端框架都能处理。
下图一为使用普通类作为参数的请求,图二为以URLSearchParams作为参数的请求。


如果你说我非要用类作为参数要怎么办呢?就得叫后端去处理你传过来的参数,像我这种自己干活的人就可以这么搞,如果你是前后端分离要嘛和后端搞好关系,要嘛老老实实用URLSearchParams

如果你直接用数据类作为参数的话,在Django中,你就没有办法使用request.POST直接处理数据了。
你需要通过

request.body

先获取POST中的参数,然后转码处理相关字符串。

获取Cookie的公共函数

简单补充一下我自己土师摸出来的公共函数的方法
看了一篇文章

Composition API如何替换Vue Mixins

所以我就尝试把getCookie的函数弄成一个公共函数
首先在components里面建一个useUtil.vue
内容如下:

<script lang="ts">
export default () => {const getCookie = (name: string) :any => {  //获取cookie函数name = name + "=";let start = document.cookie.indexOf(name),value = null;if(start>-1){let end = document.cookie.indexOf(";",start);if(end == -1){end = document.cookie.length;}value = document.cookie.substring(start+name.length,end);}return value;}const getCsfrKey = ():string => {if(getCookie('csrftoken')){return getCookie('csrftoken')}else {return ''}}return {getCookie,getCsfrKey}
}
</script><style scoped></style>

在要使用的地方:

//伪代码
import useUtil from '../components/useUtil.vue'setup(){const { getCookie , getCsfrKey } = useUtil()
}

这样就可以用了

参考:

https://www.imooc.com/article/303667

结语

CSRF的问题就暂告一段落,我要继续搬砖去了。不得不说感觉前端的设计思路和我们后端的真的差别有点大,摸起来有点左右横跳的感觉,可能前端人均大神吧。。不过从接触大前端开始感觉好像终于有点接近了。
同时继续鄙视一下百度的搜索机制,真的,这种技术类的文章内容你都不会过滤一下的?抄来抄去显示都是同一个文章,不能搭梯子的开发是真的难受。
我是跨域跨到蛋疼的llsxily,你可以叫我橘子。

DJANGO VUE3 跨域CSRF问题刨坑相关推荐

  1. django 允许跨域请求

    django允许跨域请求配置 下载corsheader pip install django-cors-headers 修改setting.py中配置 在INSTALLED_APPS中增加corshe ...

  2. django允许跨域请求配置

    2019独角兽企业重金招聘Python工程师标准>>> django允许跨域请求配置 下载corsheader pip install django-cors-headers 修改s ...

  3. Vue+Flask前后端分离 Vue3跨域配置

    Vue+Flask前后端分离 Vue3跨域配置 前端端口号为8080 后端端口号为5000 问题描述 问题解决 接口路径映射 前端端口号为8080 后端端口号为5000 后端端口API 代码片. @a ...

  4. Django Vue 跨域问题

    一.Django中设置 使用pip安装 pip install django-cors-headers setting.py中设置 INSTALLED_APPS = [...'corsheaders' ...

  5. django解决跨域问题

    什么是跨域? 跨域:指的是浏览器不能执行其他网站的脚本.它是由浏览器的同源策略造成的,是浏览器对javascript施加的安全限制 同源策略:是指协议,域名,端口都要相同,其中有一个不同都会产生跨域 ...

  6. Django框架深入了解_05 (Django中的缓存、Django解决跨域流程(非简单请求,简单请求)、自动生成接口文档)(二)

    二.跨域: 回到顶部 跨域知识介绍: 点我以前博客 跨域解决方法:CORS:跨域资源共享 CORS请求分类(简单请求和非简单请求) 简单请求(simple request):只需要在头信息之中增加一个 ...

  7. Django框架深入了解_05 (Django中的缓存、Django解决跨域流程(非简单请求,简单请求)、自动生成接口文档)(一)

    阅读目录 一.Django中的缓存: 前戏: Django中的几种缓存方式: Django中的缓存应用: 二.跨域: 跨域知识介绍: CORS请求分类(简单请求和非简单请求) 示例: 三.自动生成接口 ...

  8. Python django解决跨域请求的问题

    解决方案 1.安装django-cors-headers pip3 install django-cors-headers 2.配置settings.py文件 INSTALLED_APPS = [.. ...

  9. drf版本控制 和django缓存,跨域问题,

    drf版本控制 基于url的get传参方式 REST_FRAMEWORK={ # "DEFAULT_AUTHENTICATION_CLASSES":["app01.aut ...

最新文章

  1. c语言输入后没答案,C语言章节习题及答案(无指针)解读.doc
  2. Java与.NET 的Web Services相互调用
  3. WiFi 802.11ax
  4. 数据型驱动风控有什么内容?从蚂蚁借呗与花呗谈起~
  5. 云米冰箱能控制扫地机器人_实现家电互联,从一台云米冰箱开始
  6. HTML文件点放在手机桌面,如何把手机桌面上的文件发送到微信里
  7. leetcode 877 stone game
  8. 中国ai人工智能发展太快_新的AI计算遥远行星的速度快100,000倍
  9. Rocket - tilelink - AtomicAutomata
  10. ubuntu下载chrome等软件
  11. 2007舜宇杯ACM程序设计浙江省赛结果
  12. php cms 公文,POSCMS文件信息查看
  13. PA,MIOU,FWIOU
  14. 用sql查询姓名和身份证_查询,更新和身份
  15. 数论作业 —— 同余理论
  16. AutoML-第七章-AutoNet
  17. 计算机能力[置顶] 论计算机专业毕业生的人文素养
  18. 经典python项目源码_建议收藏,22个Python迷你项目(附源码)
  19. JAVA日期类的格式转换
  20. Hi3516开发笔记(十):Qt从VPSS中获取通道图像数据存储为jpg文件

热门文章

  1. 二十年后我发明了保姆机器人作文_未来的保姆机器人作文
  2. 2018年,中国空气质量在全球的排名,你一定想不到!
  3. 一、零基础入门微信小程序开发之创建项目工程同时完成引导页开发
  4. html5前端开发框架模板,HTML5中50个免费的Bootstrap前端框架模板
  5. 牛客刷题——Python入门总结
  6. 深入理解 Linux 2.6 的 initramfs 機制 (上)
  7. 生日祝福代码python_Python|送给朋友的生日祝福
  8. 扫地机器人可以扫纸片_扫地机器人扫的干净吗?
  9. Linux课程project----基于c/c++
  10. 2026:【例4.12】阶乘和