django-cors-headers 是一个 Django 应用程序,用于处理跨域资源共享 (CORS) 所需的服务器标头。
项目描述
将跨域资源共享 (CORS) 标头添加到响应的 Django 应用程序。这允许从其他来源向您的 Django 应用程序进行浏览器内请求。
关于 CORS
添加 CORS 标头允许您在其他域上访问您的资源。在添加标头之前了解其含义很重要,因为您可能会无意中向其他人开放您网站的私人数据。
关于这个主题的一些很好的阅读资源是:
要求
支持 Python 3.7 到 3.11。
支持 Django 3.2 到 4.1。
想要更聪明、更快速地工作? 查看我的书Boost Your Django DX,它涵盖了许多改善开发体验的方法。
设置
从pip安装:
python -m pip install django-cors-headers
然后将其添加到您安装的应用程序中:
INSTALLED_APPS = [
...,
"corsheaders",
...,
]
确保添加尾随逗号,否则您可能会收到ModuleNotFoundError (请参阅此博客文章)。
您还需要添加一个中间件类来监听响应:
MIDDLEWARE = [
...,
"corsheaders.middleware.CorsMiddleware",
"django.middleware.common.CommonMiddleware",
...,
]
CorsMiddleware应放置在尽可能高的位置,尤其是在任何可以生成响应的中间件之前,例如 Django 的CommonMiddleware或 Whitenoise 的WhiteNoiseMiddleware。如果不是之前,它将无法将 CORS 标头添加到这些响应中。
此外,如果您使用的是CORS_REPLACE_HTTPS_REFERER,它应该放在 Django 的CsrfViewMiddleware之前(见下文)。
关于
django-cors-headers由 Otto Yiu 于 2013 年 1 月创建。它从 2015 年 8 月开始无人维护,并于 2016 年 1 月分叉到 Zeste de Savoir 的 Laville Augustin 的django-cors-middleware包。2016 年 9 月,Adam Johnson、Ed Morley 和其他人从 Otto Yiu那里获得了django-cors-headers (第 110 期)的维护责任。基本上,分叉的django-cors-middleware中的所有更改都被合并回来,或者以不同的方式重新实现,因此应该可以切换回来。如果有尚未合并的功能,请打开一个关于它的问题。
django-cors-headers在当时有40 多个贡献者 ;感谢他们每一个人。
配置
在 Django 设置中配置中间件的行为。您必须至少设置以下三个设置之一:
CORS_ALLOWED_ORIGINS
CORS_ALLOWED_ORIGIN_REGEXES
CORS_ALLOW_ALL_ORIGINS
CORS_ALLOWED_ORIGINS:序列[str]
授权进行跨站点 HTTP 请求的源列表。此设置中的来源将被允许,并且请求来源将在Access-Control-Allow-Origin标头中回显给客户端。默认为[]。
Origin 由CORS RFC 第 3.2 节定义为 URI 方案 + 主机名 + 端口,或特殊值'null'或'file://'之一。默认端口(HTTPS = 443,HTTP = 80)是可选的。
特殊值null由浏览器在“隐私敏感上下文”中发送,例如当客户端从file://域运行时。根据此错误,Android 上的某些版本的 Chrome 会意外发送特殊值file://。
例子:
CORS_ALLOWED_ORIGINS = [
"https://example.com",
"https://sub.example.com",
"http://localhost:8080",
"http://127.0.0.1:9000",
]
以前此设置称为CORS_ORIGIN_WHITELIST,它仍然作为别名使用,新名称优先。
CORS_ALLOWED_ORIGIN_REGEXES:序列[str | 模式[str]]
一个字符串列表,表示与授权进行跨站点 HTTP 请求的 Origin 匹配的正则表达式。默认为[]。当CORS_ALLOWED_ORIGINS不切实际时很有用,例如当您有大量子域时。
例子:
CORS_ALLOWED_ORIGIN_REGEXES = [
r"^https://\w+\.example\.com$",
]
以前此设置称为CORS_ORIGIN_REGEX_WHITELIST,它仍然作为别名使用,新名称优先。
CORS_ALLOW_ALL_ORIGINS:布尔
如果True,将允许所有来源。其他限制允许来源的设置将被忽略。默认为False。
将此设置为True可能很危险,因为它允许任何网站向您的网站发出跨域请求。通常,您需要使用CORS_ALLOWED_ORIGINS或CORS_ALLOWED_ORIGIN_REGEXES限制允许的来源列表。
以前此设置称为CORS_ORIGIN_ALLOW_ALL,它仍然作为别名使用,新名称优先。
以下是可选设置,默认值可能就足够了。
CORS_URLS_REGEX:str | 模式[str]
一个正则表达式,它限制将为其发送 CORS 标头的 URL。默认为r'^.*$',即匹配所有 URL。当您只在站点的一部分上需要 CORS 时很有用,例如/api/的 API 。
例子:
CORS_URLS_REGEX = r"^/api/.*$"
CORS_ALLOW_METHODS:序列[str]
实际请求允许的 HTTP 动词列表。默认为:
CORS_ALLOW_METHODS = [
"DELETE",
"GET",
"OPTIONS",
"PATCH",
"POST",
"PUT",
]
默认值可以作为corsheaders.defaults.default_methods导入,因此您可以使用自定义方法对其进行扩展。这使您可以随时了解未来的任何变化。例如:
from corsheaders.defaults import default_methods
CORS_ALLOW_METHODS = list(default_methods) + [
"POKE",
]
CORS_ALLOW_HEADERS:序列[str]
您在来自浏览器的请求中允许的非标准 HTTP 标头列表。在对预检请求的响应中设置Access-Control-Allow-Headers标头。默认为:
CORS_ALLOW_HEADERS = [
"accept",
"accept-encoding",
"authorization",
"content-type",
"dnt",
"origin",
"user-agent",
"x-csrftoken",
"x-requested-with",
]
默认值可以作为corsheaders.defaults.default_headers导入,因此您可以使用自定义标题对其进行扩展。这使您可以随时了解未来的任何变化。例如:
from corsheaders.defaults import default_headers
CORS_ALLOW_HEADERS = list(default_headers) + [
"my-custom-header",
]
CORS_EXPOSE_HEADERS:序列[str]
除了默认的安全列表标头之外,要向浏览器公开的额外 HTTP 标头列表。如果非空,则在Access-Control-Expose-Headers标头中声明。默认为[]。
CORS_PREFLIGHT_MAX_AGE:整数
浏览器可以缓存预检响应的秒数。这会在预检响应中设置Access-Control-Max-Age标头。如果这是 0(或任何虚假值),则不会发送最大年龄标头。默认为86400(一天)。
注意:浏览器在某些“非简单”请求之前 发送预检请求,以检查它们是否被允许。在CORS MDN 文章中阅读有关它的更多信息。
CORS_ALLOW_CREDENTIALS:布尔
如果为True,cookie 将被允许包含在跨站点 HTTP 请求中。这会在预检和正常响应中设置Access-Control-Allow-Credentials标头。默认为False。
注意:在 Django 2.1 中添加了SESSION_COOKIE_SAMESITE设置,默认设置为“Lax”,这将阻止 Django 的会话 cookie 跨域发送。如果您需要绕过此安全限制,请将设置更改为无。
CSRF 集成
大多数站点都需要利用 Django 提供的跨站点请求伪造保护。CORS 和 CSRF 是分开的,Django 无法使用您的 CORS 配置来免除站点的Referer检查它对安全请求所做的检查。这样做的方法是使用它的CSRF_TRUSTED_ORIGINS 设置。例如:
CORS_ALLOWED_ORIGINS = [
"http://read.only.com",
"http://change.allowed.com",
]
CSRF_TRUSTED_ORIGINS = [
"http://change.allowed.com",
]
CORS_REPLACE_HTTPS_REFERER:布尔
CSRF_TRUSTED_ORIGINS是在 Django 1.9 中引入的,因此早期版本的用户将需要一个替代解决方案。如果CORS_REPLACE_HTTPS_REFERER为 True,CorsMiddleware会将Referer标头更改为在 CORS 检查通过时将通过 Django 的 CSRF 检查的内容。默认为 False。
请注意,与CSRF_TRUSTED_ORIGINS不同,此设置不允许您区分受CORS信任读取资源的域和受信任通过避免 CSRF 保护来更改资源的域。
启用此功能 后,您还应该在MIDDLEWARE_CLASSES中的django.middleware.csrf.CsrfViewMiddleware之后 添加corsheaders.middleware.CorsPostCsrfMiddleware以撤消引用替换:
MIDDLEWARE_CLASSES = [
...,
"corsheaders.middleware.CorsMiddleware",
...,
"django.middleware.csrf.CsrfViewMiddleware",
"corsheaders.middleware.CorsPostCsrfMiddleware",
...,
]
信号
如果您的用例需要的不仅仅是上述配置,您可以附加代码以检查是否应允许给定请求。例如,这可用于从模型中读取您允许的来源列表。将任意数量的处理程序附加到check_request_enabled Django 信号,该信号提供请求参数(在处理程序中使用**kwargs以防止将来添加任何参数)。如果任何附加到信号的处理程序返回一个真实值,则该请求将被允许。
例如,您可以定义这样的处理程序:
# myapp/handlers.py
from corsheaders.signals import check_request_enabled
from myapp.models import MySite
def cors_allow_mysites(sender, request, **kwargs):
return MySite.objects.filter(host=request.headers["Origin"]).exists()
check_request_enabled.connect(cors_allow_mysites)
然后在应用准备就绪时使用Django AppConfig连接它:
# myapp/__init__.py
default_app_config = "myapp.apps.MyAppConfig"
# myapp/apps.py
from django.apps import AppConfig
class MyAppConfig(AppConfig):
name = "myapp"
def ready(self):
# Makes sure all signal handlers are connected
from myapp import handlers # noqa
该信号的一个常见用例是允许所有源访问 URL 的子集,同时允许一组正常的源访问所有URL。仅使用普通配置是不可能的,但可以使用信号处理程序来实现。
首先将CORS_ALLOWED_ORIGINS设置为允许访问每个 URL 的受信任来源列表,然后将处理程序添加到 check_request_enabled以允许 CORS,而不管不受限制的 URL 的来源如何。例如:
# myapp/handlers.py
from corsheaders.signals import check_request_enabled
def cors_allow_api_to_everyone(sender, request, **kwargs):
return request.path.startswith("/api/")
check_request_enabled.connect(cors_allow_api_to_everyone)