假设您在某个域中拥有后端API。
并且您在另一个域或同一域(或在移动应用程序中)的不同路径中具有前端。
而且,您希望使用用户名和密码为前端提供一种与后端进行身份验证的方法。
我们可以使用OAuth2通过FastAPI进行构建。
但是,让我们节省阅读完整的长期规范的时间,仅是查找所需的那些小信息。
让我们使用FastAPI提供的工具来处理安全性。

How it looks

首先,让我们使用代码并查看其工作原理,然后再回来了解发生了什么。

创建main.py

将示例复制到文件main.py中:

  1. from fastapi import Depends, FastAPI
  2. from fastapi.security import OAuth2PasswordBearer
  3. app = FastAPI()
  4. oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/token")
  5. @app.get("/items/")
  6. async def read_items(token: str = Depends(oauth2_scheme)):
  7. return {"token": token}

运行它


:::info 信息
首先安装python-multipart.
例如。pip install python-multipart.
这是因为OAuth2使用“表单数据”发送usernamepassword。 :::

运行例子:

  1. uvicorn main:app --reload

检查它

转到位于以下位置的交互式文档:[http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs)
您将看到如下内容:安全-第一步 - 图1

:::tips 验证按钮
您已经有了一个闪亮的新“授权”按钮。
并且您的路径操作在右上角有一个小的锁定,您可以单击它。 :::

如果单击它,您将获得一些授权表单,用于输入usernamepassword(以及其他可选字段):
安全-第一步 - 图2

:::tips 注意
不管您在表格中键入什么,都将无法使用。但是我们会到达那里。 :::

当然,这不是最终用户的前端,但它是一个很好的自动工具,可以交互式地记录您所有的API。
前端团队(也可以是您自己)可以使用它。
第三方应用程序和系统可以使用它。
您也可以自己使用它来调试,检查和测试同一应用程序。

password 流程

现在让我们回到过去,了解所有内容。
password“流”是OAuth2中定义的用于处理安全性和身份验证的一种方式(“流”)。
OAuth2的设计使后端或API可以独立于对用户进行身份验证的服务器。
但是在这种情况下,相同的FastAPI应用程序将处理API和身份验证。
因此,让我们从简化的角度进行回顾:

  • 用户在前端输入usenamepasword,然后按Enter。
  • 前端(在用户浏览器中运行)将用户名和密码发送到我们API中的特定URL。
  • API检查该usernamepassword,并以“令牌”作为响应
    • “令牌”只是一个包含一些内容的字符串,我们稍后可以使用它来验证该用户。
    • 通常,令牌设置为在一段时间后过期
      • 因此,用户稍后将不得不再次登录。
      • 而且,如果令牌被盗,则风险会降低。它不像将永远有效的永久密钥(在大多数情况下)。
  • 前端将该令牌临时存储在某个地方。
  • 用户单击前端以转到前端Web应用程序的另一部分。
  • 前端需要从API中获取更多数据。
    • 但是它需要特定端点的身份验证。
    • 因此,为了使用我们的API进行身份验证,它会发送标头Authorization,其值为Bearer加上令牌。
    • 如果令牌包含foobar,则Authorization标头的内容为:Bearer foobar

      FastAPI的OAuth2PasswordBearer

      FastAPI提供了几种处于不同抽象级别的工具来实现这些安全功能。
      在此示例中,我们将使用Bearer令牌将OAuth2与密码流结合使用。

:::info 信息
“承载”令牌不是唯一的选择。
但这是我们用例的最佳选择。
除非您是OAuth2专家并且确切知道为什么还有另一种更适合您的需求的方法,否则它可能是大多数用例的最佳选择。
在这种情况下,FastAPI还为您提供了构建它的工具。 :::

OAuth2PasswordBearer是我们创建的类,该类传递URL的参数,客户端(在用户浏览器中运行的前端)可以在其中使用该参数发送usernamepassword并获取令牌。

  1. from fastapi import Depends, FastAPI
  2. from fastapi.security import OAuth2PasswordBearer
  3. app = FastAPI()
  4. oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/token")
  5. @app.get("/items/")
  6. async def read_items(token: str = Depends(oauth2_scheme)):
  7. return {"token": token}

它不会创建该端点/路径操作,而是声明该URL是客户端应用于获取令牌的URL。该信息在OpenAPI中使用,然后在交互式API文档系统中使用。

:::info 信息
如果您是非常严格的“ Pythonista”,则可能不喜欢参数名称tokenUrl而不是token_url的样式。
这是因为它使用的名称与OpenAPI规范中的名称相同。这样,如果您需要更多地研究这些安全方案中的任何一种,就可以复制并粘贴它以找到有关此方案的更多信息。 :::

oauth2_scheme变量是OAuth2PasswordBearer的实例,但它也是“可调用的”。
它可以被称为:

  1. oauth_scheme(some, parameters)

因此,他需要和Depends一起使用。

使用

现在,您可以在Depends依赖项中传递该oauth2_scheme

  1. from fastapi import Depends, FastAPI
  2. from fastapi.security import OAuth2PasswordBearer
  3. app = FastAPI()
  4. oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/token")
  5. @app.get("/items/")
  6. async def read_items(token: str = Depends(oauth2_scheme)):
  7. return {"token": token}

此依赖关系将提供一个str,该str被分配给路径操作函数的参数token
FastAPI将知道它可以使用此依赖关系在OpenAPI架构(和自动API文档)中定义“安全方案”。

:::tips 详细教程
FastAPI将知道它可以使用类OAuth2PasswordBearer(在依赖项中声明)在OpenAPI中定义安全方案,因为它继承自`fastapi.security.oauth2.OAuth2,而后者又继承自fastapi.security.base.SecurityBase
与OpenAPI(和自动API文档)集成的所有安全实用程序都继承自SecurityBase,这就是FastAPI知道如何将其集成到OpenAPI中的方式。 :::

what is does

它将去寻找该Authorization标头的请求,检查该值是否为Bearer加一些令牌,并将令牌作为str返回。
如果没有看到Authorization标头,或者该值没有Bearer令牌,它将直接以401状态码错误(UNAUTHORIZED)进行响应。
您甚至不必检查令牌是否存在即可返回错误。您可以确定,如果执行了函数,则该令牌中将有一个str。
您可以在交互式文档中尝试一下:
安全-第一步 - 图3
我们尚未验证令牌的有效性,但这已经是一个开始。

概括

因此,仅需增加3或4行,您就已经具有某种原始的安全性形式。