CORS跨站请求
目录
-
跨域的三大分类
- xss: 跨站脚本攻击
- csrf: 跨站请求伪造
- cors: 跨域资源共享
-
同源策略
同源策略是浏览器的安全策略, 如果浏览器对javascript没有同源策略的保护, 那么一些重要的机密网站将会很危险. 同源策略: 不允许不同域之间直接通信直接通信. 请求的url地址, 必须与浏览器上的url地址处于同域上, 也就是域名, 端口, 协议相同. 比如:我在本地上的域名是127.0.0.1:8000, 请求另外一个域名: 127.0.0.1:8001 浏览器上就会报错,.
-
跨站请求测试
-
项目1(端口号为8008)
# 路由层 from django.contrib import admin from django.urls import path, re_path from app01 import views urlpatterns = [ path('admin/', admin.site.urls), re_path(r'^get_data/', views.get_data) ]
# 视图层 from django.http import JsonResponse # Create your views here. def get_data(request): print(f'{request.method} 请求访问 get_data') return JsonResponse({'k1': 'v1'})
修改端口号为8008
启动项目, 浏览器访问 http://127.0.0.1:8008/get_data/
-
项目2 (端口号为8000)
# 路由层 from django.contrib import admin from django.urls import path, re_path from app01 import views urlpatterns = [ path('admin/', admin.site.urls), re_path(r'^index/', views.index) ]
# 视图层 from django.shortcuts import render # Create your views here. def index(request): return render(request, 'index.html')
模板层代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>客户端</title> <script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script> </head> <body> <button onclick="click1">发送请求</button> </body> <script> function click1() { $.ajax({ url: 'http://127.0.0.1:8008/get_data/', type: 'get', success: function (args) { console.log(args) } }) } </script> </html>
1. 先启动server项目, 在启动client项目, 2. 浏览器访问 https://127.0.0.1:8000/index/ 3. 点击按钮向https://127.0.0.1:8008/get_data/ 4. 报错已拦截跨源请求, 同源策略禁止读取... 原因:CORS 头缺少 'Access-Control-Allow-Origin' 5. 可以看到服务端是收到了请求, 并返回了数据, 最后被浏览器拦截了
-
-
CORS简单/非简单请求
只要同时满足以下两大条件,就属于简单请求, 凡是不同时满足下面两个条件, 就属于非简单请求.
- 请求方法是以下三种方法之一:
- HEAD
- GET
- POST
- HTTP的头信息是以下几种字段:
- Accept: 发送端(客户端)希望接受的数据类型.
- Accept-Language: 希望采用的语言或语言组合.
- Content-Language: 用来表示报文体(实体数据)使用的语言(ch,fr,en,ja等).
- Last-Event-ID: 标识最后一次接受的event id.
- Content-Type: 发送端(客户端|服务器)发送的实体数据的数据类型.
默认只限于三个值application/x-www-form-urlencoded, multipart/form-data, text/plain
浏览器对这两种请求的处理, 是不一样的.
- 简单请求:只会发送一次请求
- 为返回数据对象时, 在响应头中添加,Access-Control-Allow-Origin(访问控制允许源)的信息则可以资源共享.
- 非简单请求: 会发送两次请求, 第一次发送OPTIONS请求用于做预检,
- 预检请求时, 允许请求方式则需服务器设置响应头: Access-Control-Request-Method
- 预检请求时, 允许请求头则需服务器设置响应头:Access-Control-Request-Headers (允许额外的头或数据类型)
- 才会再以次发送请求用于数据传输。
# 本质 跨域资源共享, 本质就是在响应头部加入允许, 允许某些域, 允许某些头, 添加的域和头就能正常访问. 简单请求需要允许访问的域, 非简单请需要先设置允许某些头. 再设置域.
-
简单请求资源共享
在项目1的视图函数中, 返回数据对象的时候在响应头中添加Access-Control-Allow-Origin的信息. HttpResponse[key] = value 在响应头中添加数据 Access-Control-Allow-Origin为键, 允许跨站获取资源的地址为值.
from django.shortcuts import render from django.http import JsonResponse # Create your views here. def get_data(request): print(f'{request.method} 请求访问 get_data') response = JsonResponse({'k1': 'v1'}) # * 代表允许所有求访问 # response['Access-Control-Allow-Origin'] = '*' # 单独配置 response['Access-Control-Allow-Origin'] = 'http://127.0.0.1:8000' return response
使用使用rest_farmework的Response返回数据, 则为Response的headers响应头参数设置{'Access-Control-Allow-Origin': '*'}
-
非简单请求资源共享
- 修改项目2模板文件, 提交json格式的数据到后端
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>客户端</title> <script src="http://code.jquery.com/jquery-2.1.1.min.js"></script> </head> <body> <button onclick="click1()">发送json数据</button> </body> <script> function click1() { $.ajax({ url: 'http://127.0.0.1:8008/get_data/', type: 'post', contentType: 'application/json', data: JSON.stringify({'k1': 'v1'}), success: function (args) { console.log(args) } }) } </script> </html>
- 将项目1的csrf检验关闭
MIDDLEWARE = [ ... # 'django.middleware.csrf.CsrfViewMiddleware', ...
- 先启动项目1, 在启动项2, 浏览器访问 127.0.0.1:8000/indiex/
- 修改项目1的视图函数
def get_data(request): print(f'{request.method} 请求访问 get_data',) response = JsonResponse({'k1': 'v1'}) # 如果是非简单请求发送的是OPTIONS请求, 在响应中添加 访问控制允许标头的信息 if request.method == 'OPTIONS': response['Access-Control-Allow-Headers'] = 'Content-Type' response['Access-Control-Allow-Origin'] = 'http://127.0.0.1:8000' return response
- 先启动项目1, 在启动项2, 浏览器访问 127.0.0.1:8000/indiex/
- 修改项目2模板文件, 提交json格式的数据到后端
- 请求方法是以下三种方法之一:
-
自定制中间件中实现资源共享
-
新建CorsMiddleware Cors中间件
# utils文件内 from django.utils.deprecation import MiddlewareMixin class CorsMiddleware(MiddlewareMixin): def process_response(self, request, response): if request.method == 'OPTIONS': # 允许头的之后 Content-Type的不在限制 response['Access-Control-Allow-Headers'] = 'Content-Type' response['Access-Control-Allow-Origin'] = 'http://127.0.0.1:8000' return response
-
将自定义中间件添加到配置文件中
MIDDLEWARE = [ 'utils.CorsMiddleware.CorsMiddleware', ...
-
将视图函数中的Cors配置删除
def get_data(request): print(f'{request.method} 请求访问 get_data',) response = JsonResponse({'k1': 'v1'}) return response
-
测试
先启动项目1, 在启动项2, 浏览器访问 127.0.0.1:8000/indiex/
-
-
django-cors-header模块
-
安装模块
默认安装最新的版本 需要django3.2版本及以上
pip install django-cors-headers==2
-
注册app
django-cors-header是一个app, 需要注册在app列表中才能使用
INSTALLED_APPS = [ ... 'corsheaders', ]
-
添加中间件
MIDDLEWARE = [ 'corsheaders.middleware.CorsMiddleware', # 注册自己的中间件 # 'utils.CorsMiddleware.CorsMiddleware', ...
-
配置文件setting.py中配置django-cors-header使用的参数
# CORS_允许_凭据 CORS_ALLOW_CREDENTIALS = True # CORS起源允许所有 CORS_ORIGIN_ALLOW_ALL = True # 允许的方法 CORS_ALLOW_METHODS = ( 'DELETE', 'GET', 'OPTIONS', 'PATCH', 'POST', 'PUT', ) # 允许的标头 CORS_ALLOW_HEADERS = ( 'authorization', 'content-type', )
点击查看更多配置代码
# CORS_允许_凭据 CORS_ALLOW_CREDENTIALS = True # CORS起源允许所有 CORS_ORIGIN_ALLOW_ALL = True # CORS起源白名单 需要https:// 开头 CORS_ORIGIN_WHITELIST = ('地址1', '地址1') # 允许的方法 CORS_ALLOW_METHODS = ( 'DELETE', 'GET', 'OPTIONS', 'PATCH', 'POST', 'PUT', 'VIEW', ) # 允许的标头 CORS_ALLOW_HEADERS = ( 'XMLHttpRequest', 'X_FILENAME', 'accept-encoding', 'authorization', 'content-type', 'dnt', 'origin', 'user-agent', 'x-csrftoken', 'x-requested-with', 'Pragma', )
-