跳转到主要内容

aiohttp的CORS支持

项目描述

aiohttp的CORS支持

aiohttp_cors 库实现了对 跨源资源共享(CORS) 的支持,用于 aiohttp 异步 HTTP 服务器。

直接跳转到 使用方法 部分查看如何使用 aiohttp_cors

同源策略

Web 安全模型与 同源策略(SOP) 密切相关。简而言之:网页不能 读取 与请求页面源不匹配的资源,但可以 嵌入(或 执行)资源,并对资源的 写入 具有有限的能力。

页面的源由 标准 定义为元组 (schema, host, port)(在 Internet Explorer 中有一个值得注意的例外:它不使用端口号来定义源,而是使用它自己的 安全区域)。

可以 嵌入 意味着来自其他源的资源可以被嵌入到页面中,例如通过使用 <script src="..."><img src="..."><iframe src="...">

不能 读取 意味着来自其他源的资源 无法被页面获取( —— 任何可以重建资源的信息)。例如,页面可以 嵌入 图像,使用 <img src="...">,但它无法获取特定像素的信息,因此页面无法重建原始图像(尽管来自其他资源的一些信息可能仍然会泄露:例如,页面可以读取嵌入图像的尺寸)。

有限的能力 写入 意味着页面可以向其他源发送具有有限 Content-Type 值和头部的 POST 请求。

对从其他源读取资源的限制与浏览器使用的身份验证机制有关:当浏览器读取(下载)资源时,它会自动发送用户先前为该资源授权的所有安全凭证(例如 cookies、HTTP 基本身份验证)。

例如,如果允许 读取,并且用户在某家互联网银行进行了身份验证,恶意页面将能够嵌入互联网银行页面(因为身份验证是由浏览器完成的,所以它可以像用户直接导航到互联网银行页面一样嵌入),然后通过读取嵌入页面的 (这可能不仅限于源代码,例如,嵌入的互联网银行页面的截图)来读取用户的私人信息。

跨源资源共享

跨源资源共享(CORS) 允许覆盖特定资源的 SOP。

简而言之,CORS 以以下方式工作。

当页面 https://client.example.com 请求(读取)具有其他源的资源 https://server.example.com/resource 时,浏览器在 HTTP 请求中隐式附加 Origin: https://client.example.com 头部,有效地要求服务器给予 https://client.example.com 页面对该资源的读取权限。

GET /resource HTTP/1.1
Origin: https://client.example.com
Host: server.example.com

如果服务器允许页面访问该资源,它将响应带有 Access-Control-Allow-Origin: https://client.example.com HTTP 头部的资源(可选地允许向页面暴露自定义服务器头并启用在服务器资源上使用用户凭证)。

Access-Control-Allow-Origin: https://client.example.com
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: X-Server-Header

浏览器检查服务器是否响应了适当的 Access-Control-Allow-Origin 头部,并根据此允许或拒绝页面对获取的资源进行访问。

CORS 规范设计得如此,以至于不熟悉 CORS 的服务器除了 SOP 允许的信息外,不会泄露任何其他信息。

要请求带有自定义头或使用自定义HTTP方法(例如 PUTDELETE)的资源,这些方法在SOP中不允许,启用CORS的浏览器首先使用 OPTIONS 方法向资源发送 预检请求,在其中他查询使用特定方法和头对资源的访问权限

OPTIONS / HTTP/1.1
Origin: https://client.example.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Client-Header

CORS启用服务器响应请求的方法是否允许以及哪些指定的头允许

Access-Control-Allow-Origin: https://client.example.com
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: PUT
Access-Control-Allow-Headers: X-Client-Header
Access-Control-Max-Age: 3600

浏览器检查预检请求的响应,如果实际请求被允许,则进行实际请求。

安装

您可以从PyPI或从git将 aiohttp_cors 作为典型的Python库安装

$ pip install aiohttp_cors

请注意,aiohttp_cors 需要 Python >= 3.4.1 和 aiohttp >= 1.1 版本。

用法

要使用 aiohttp_cors,您需要配置应用程序并在您想要公开的资源(和路由)上启用CORS

import asyncio
from aiohttp import web
import aiohttp_cors

@asyncio.coroutine
def handler(request):
    return web.Response(
        text="Hello!",
        headers={
            "X-Custom-Server-Header": "Custom data",
        })

app = web.Application()

# `aiohttp_cors.setup` returns `aiohttp_cors.CorsConfig` instance.
# The `cors` instance will store CORS configuration for the
# application.
cors = aiohttp_cors.setup(app)

# To enable CORS processing for specific route you need to add
# that route to the CORS configuration object and specify its
# CORS options.
resource = cors.add(app.router.add_resource("/hello"))
route = cors.add(
    resource.add_route("GET", handler), {
        "http://client.example.org": aiohttp_cors.ResourceOptions(
            allow_credentials=True,
            expose_headers=("X-Custom-Server-Header",),
            allow_headers=("X-Requested-With", "Content-Type"),
            max_age=3600,
        )
    })

每个路由都有自己的CORS配置,通过 CorsConfig.add() 方法传递。

CORS配置是从源到该源选项的映射。

在上面的示例中,CORS被配置为在路径 /hello 下以及HTTP方法 GET 下的资源,在CORS的上下文中

  • 此资源将仅对 http://client.example.org 源可用。

  • 允许将凭据传递到此资源。

  • 此资源将向客户端公开 X-Custom-Server-Header 服务器头。

  • 客户端将被允许将 X-Requested-WithContent-Type 头传递到服务器。

  • 预检请求将被客户端缓存3600秒。

资源仅对明确指定的源可用。您可以使用特殊 * 源指定“所有其他源”

cors.add(route, {
        "*":
            aiohttp_cors.ResourceOptions(allow_credentials=False),
        "http://client.example.org":
            aiohttp_cors.ResourceOptions(allow_credentials=True),
    })

在这里,由 route 指定的资源将对所有带有不允许凭据传递的源可用,并且仅对 http://client.example.org 允许凭据传递。

默认情况下,ResourceOptions 将在没有允许的CORS选项的情况下构建。这意味着,资源将仅对指定的源使用CORS可用,但客户端将不允许发送凭据,或发送非简单头,或从服务器读取非简单头。

要启用发送或接收所有头,您可以使用特殊值 * 而不是头序列

cors.add(route, {
        "http://client.example.org":
            aiohttp_cors.ResourceOptions(
                expose_headers="*",
                allow_headers="*"),
    })

您可以使用 aiohttp_cors.setup()defaults 参数指定默认CORS启用资源选项

cors = aiohttp_cors.setup(app, defaults={
        # Allow all to read all CORS-enabled resources from
        # http://client.example.org.
        "http://client.example.org": aiohttp_cors.ResourceOptions(),
    })

# Enable CORS on routes.

# According to defaults POST and PUT will be available only to
# "http://client.example.org".
hello_resource = cors.add(app.router.add_resource("/hello"))
cors.add(hello_resource.add_route("POST", handler_post))
cors.add(hello_resource.add_route("PUT", handler_put))

# In addition to "http://client.example.org", GET request will be
# allowed from "http://other-client.example.org" origin.
cors.add(hello_resource.add_route("GET", handler), {
        "http://other-client.example.org":
            aiohttp_cors.ResourceOptions(),
    })

# CORS will be enabled only on the resources added to `CorsConfig`,
# so following resource will be NOT CORS-enabled.
app.router.add_route("GET", "/private", handler)

您还可以为资源指定默认选项

# Allow POST and PUT requests from "http://client.example.org" origin.
hello_resource = cors.add(app.router.add_resource("/hello"), {
        "http://client.example.org": aiohttp_cors.ResourceOptions(),
    })
cors.add(hello_resource.add_route("POST", handler_post))
cors.add(hello_resource.add_route("PUT", handler_put))

资源CORS配置允许使用 allow_methods 选项,该选项明确指定了允许来源(或 * 为所有HTTP方法)的HTTP方法列表。使用此选项,不需要将所有资源路由添加到CORS配置对象中

# Allow POST and PUT requests from "http://client.example.org" origin.
hello_resource = cors.add(app.router.add_resource("/hello"), {
        "http://client.example.org":
            aiohttp_cors.ResourceOptions(allow_methods=["POST", "PUT"]),
    })
# No need to add POST and PUT routes into CORS configuration object.
hello_resource.add_route("POST", handler_post)
hello_resource.add_route("PUT", handler_put)
# Still you can add additional methods to CORS configuration object:
cors.add(hello_resource.add_route("DELETE", handler_delete))

以下是如何为所有来源启用所有CORS功能的示例

cors = aiohttp_cors.setup(app, defaults={
    "*": aiohttp_cors.ResourceOptions(
            allow_credentials=True,
            expose_headers="*",
            allow_headers="*",
        )
})

# Add all resources to `CorsConfig`.
resource = cors.add(app.router.add_resource("/hello"))
cors.add(resource.add_route("GET", handler_get))
cors.add(resource.add_route("PUT", handler_put))
cors.add(resource.add_route("POST", handler_put))
cors.add(resource.add_route("DELETE", handler_delete))

旧的路由API受到支持——您可以像以前一样使用 router.add_routerrouter.register_route,尽管这种用法不推荐

cors.add(
    app.router.add_route("GET", "/hello", handler), {
        "http://client.example.org": aiohttp_cors.ResourceOptions(
            allow_credentials=True,
            expose_headers=("X-Custom-Server-Header",),
            allow_headers=("X-Requested-With", "Content-Type"),
            max_age=3600,
        )
    })

您可以通过访问路由列表在路由器中启用所有添加的路由的CORS

# Setup application routes.
app.router.add_route("GET", "/hello", handler_get)
app.router.add_route("PUT", "/hello", handler_put)
app.router.add_route("POST", "/hello", handler_put)
app.router.add_route("DELETE", "/hello", handler_delete)

# Configure default CORS settings.
cors = aiohttp_cors.setup(app, defaults={
    "*": aiohttp_cors.ResourceOptions(
            allow_credentials=True,
            expose_headers="*",
            allow_headers="*",
        )
})

# Configure CORS on all routes.
for route in list(app.router.routes()):
    cors.add(route)

您还可以在 web.View 上使用 CorsViewMixin

class CorsView(web.View, CorsViewMixin):

    cors_config = {
        "*": ResourceOption(
            allow_credentials=True,
            allow_headers="X-Request-ID",
        )
    }

    @asyncio.coroutine
    def get(self):
        return web.Response(text="Done")

    @custom_cors({
        "*": ResourceOption(
            allow_credentials=True,
            allow_headers="*",
        )
    })
    @asyncio.coroutine
    def post(self):
        return web.Response(text="Done")

cors = aiohttp_cors.setup(app, defaults={
    "*": aiohttp_cors.ResourceOptions(
            allow_credentials=True,
            expose_headers="*",
            allow_headers="*",
        )
})

cors.add(
    app.router.add_route("*", "/resource", CorsView),
    webview=True)

安全

待办:填写此内容

开发

设置开发环境

# Clone sources repository:
git clone https://github.com/aio-libs/aiohttp_cors.git .
# Create and activate virtual Python environment:
python3 -m venv env
source env/bin/activate
# Install requirements and aiohttp_cors into virtual environment
pip install -r requirements-dev.txt

运行测试

tox

仅在当前环境中运行运行时测试

py.test

仅运行静态代码分析检查

tox -e check

运行Selenium测试

要使用Firefox WebDriver运行Selenium测试,您需要安装Firefox。

要使用Chromium WebDriver运行Selenium测试,您需要

  1. 安装Chrome驱动程序。在Ubuntu 14.04中,它位于chromium-chromedriver软件包中。

  2. chromedriver添加到PATH,或将环境变量WEBDRIVER_CHROMEDRIVER_PATH设置为chromedriver,例如,在Ubuntu 14.04上 WEBDRIVER_CHROMEDRIVER_PATH=/usr/lib/chromium-browser/chromedriver

发布流程

要从master分支的当前版本发布版本vA.B.C,您需要

  1. 创建本地分支vA.B.C

  2. CHANGES.rst中将发布日期设置为今天。

  3. aiohttp_cors/__about__.py中将版本从A.B.Ca0更改为A.B.C

  4. 创建带有vA.B.C分支的拉取请求,等待所有检查成功完成(Travis和Appveyor)。

  5. 将拉取请求合并到master分支。

  6. 更新并检出master分支。

  7. 为发布版本在GitHub上创建并推送标签

    git tag vA.B.C
    git push --tags

    现在Travis应该再次运行测试,并在PyPI上构建和部署wheel。

    如果由于某些原因Travis发布失败,请使用以下步骤进行手动发布上传。

    1. 安装setuptools和pip的新版本。安装用于构建wheel的wheel。安装twine以上传到PyPI。

      pip install -U pip setuptools twine wheel
    2. ~/.pypirc中配置PyPI凭据。

    3. 构建发行版

      rm -rf build dist; python setup.py sdist bdist_wheel
    4. 将新版本上传到PyPI

      twine upload dist/*
  8. 如有必要,在GitHub上编辑发布说明。

  9. https://groups.google.com/forum/#!forum/aio-libs上的邮件列表上宣布新版本。

发布后步骤

  1. CHANGES.rst中添加下一个版本的模板。

  2. aiohttp_cors/__about__.py中将版本从A.B.C更改为A. ( B + 1) .0a0

错误

请在GitHub上报告错误、问题、功能请求等。

许可证

版权所有 2015 Vladimir Rutsky <vladimir@rutsky.org>。

许可协议为Apache License, Version 2.0,有关详细信息,请参阅LICENSE文件。

CHANGES

0.7.0 (2018-03-05)

  • 使网络视图检查隐式且基于类型 (#159)

  • 禁用Python 3.4支持 (#156)

  • 支持aiohttp 3.0+ (#155)

0.6.0 (2017-12-21)

  • 支持通过CorsViewMixin的aiohttp视图 (#145)

0.5.3 (2017-04-21)

  • 修复Python 3.6上安装typing的问题。

0.5.2 (2017-03-28)

  • 修复测试与aiohttp 2.0的兼容性。此版本和版本v0.5.0应在aiohttp 2.0上工作。

0.5.1 (2017-03-23)

  • 强制要求aiohttp版本小于2.0。将支持下一个版本的新aiohttp版本。

0.5.0 (2016-11-18)

  • 修复与aiohttp 1.1的兼容性

0.4.0 (2016-04-04)

  • 修复对在aiohttp 0.21.0中引入的新资源对象的兼容性。现在支持的aiohttp最小版本是0.21.4。

  • 支持新的资源对象。您可以为资源指定默认配置,并使用allow_methods显式列出允许的方法(或*表示所有HTTP方法)

    # Allow POST and PUT requests from "http://client.example.org" origin.
    hello_resource = cors.add(app.router.add_resource("/hello"), {
            "http://client.example.org":
                aiohttp_cors.ResourceOptions(
                    allow_methods=["POST", "PUT"]),
        })
    # No need to add POST and PUT routes into CORS configuration object.
    hello_resource.add_route("POST", handler_post)
    hello_resource.add_route("PUT", handler_put)
    # Still you can add additional methods to CORS configuration object:
    cors.add(hello_resource.add_route("DELETE", handler_delete))
  • AbstractRouterAdapter已完全重写以更不依赖于Router。

0.3.0 (2016-02-06)

  • UrlDistatcherRouterAdapter 重命名为 UrlDispatcherRouterAdapter

  • 将最大支持的 aiohttp 版本设置为 0.20.2,有关详细信息,请参阅错误编号 #30。

0.2.0 (2015-11-30)

  • 将 ABCs 从 aiohttp_cors.router_adapter 移动到 aiohttp_cors.abc

  • RouterAdapter 重命名为 AbstractRouterAdapter

  • 修复了配置命名路由的 CORS 时的错误。

0.1.0 (2015-11-05)

  • 初始发布。

项目详情


下载文件

下载适用于您平台文件的文件。如果您不确定选择哪个,请了解更多关于 安装包 的信息。

源分布

aiohttp-cors-0.7.0.tar.gz (36.0 kB 查看散列值)

上传日期

构建分布

aiohttp_cors-0.7.0-py3-none-any.whl (27.6 kB 查看散列值)

上传日期 Python 3

支持者