codecamp

FastAPI教程 获取当前用户

在上一章节中,(基于依赖项注入系统的)安全系统向路径操作函数提供了一个 str 类型的 token:

from fastapi import Depends, FastAPI
from fastapi.security import OAuth2PasswordBearer

app = FastAPI()

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")


@app.get("/items/")
async def read_items(token: str = Depends(oauth2_scheme)):
    return {"token": token}

但这还不是很实用。

让我们来使它返回当前用户给我们。

创建一个用户模型

首先,让我们来创建一个用户 Pydantic 模型。

与使用 Pydantic 声明请求体的方式相同,我们可以在其他任何地方使用它:

from typing import Optional

from fastapi import Depends, FastAPI
from fastapi.security import OAuth2PasswordBearer
from pydantic import BaseModel

app = FastAPI()

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")


class User(BaseModel):
    username: str
    email: Optional[str] = None
    full_name: Optional[str] = None
    disabled: Optional[bool] = None


def fake_decode_token(token):
    return User(
        username=token + "fakedecoded", email="john@example.com", full_name="John Doe"
    )


async def get_current_user(token: str = Depends(oauth2_scheme)):
    user = fake_decode_token(token)
    return user


@app.get("/users/me")
async def read_users_me(current_user: User = Depends(get_current_user)):
    return current_user

创建一个 get_current_user 依赖项

让我们来创建一个 get_current_user 依赖项。

还记得依赖项可以有子依赖项吗?

get_current_user 将具有一个我们之前所创建的同一个 oauth2_scheme 作为依赖项。

与我们之前直接在路径操作中所做的相同,我们新的依赖项 get_current_user 将从子依赖项 oauth2_scheme 中接收一个 str 类型的 token:

from typing import Optional

from fastapi import Depends, FastAPI
from fastapi.security import OAuth2PasswordBearer
from pydantic import BaseModel

app = FastAPI()

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")


class User(BaseModel):
    username: str
    email: Optional[str] = None
    full_name: Optional[str] = None
    disabled: Optional[bool] = None


def fake_decode_token(token):
    return User(
        username=token + "fakedecoded", email="john@example.com", full_name="John Doe"
    )


async def get_current_user(token: str = Depends(oauth2_scheme)):
    user = fake_decode_token(token)
    return user


@app.get("/users/me")
async def read_users_me(current_user: User = Depends(get_current_user)):
    return current_user

获取用户

get_current_user 将使用我们创建的(伪)工具函数,该函数接收 str 类型的令牌并返回我们的 Pydantic User 模型:

from typing import Optional

from fastapi import Depends, FastAPI
from fastapi.security import OAuth2PasswordBearer
from pydantic import BaseModel

app = FastAPI()

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")


class User(BaseModel):
    username: str
    email: Optional[str] = None
    full_name: Optional[str] = None
    disabled: Optional[bool] = None


def fake_decode_token(token):
    return User(
        username=token + "fakedecoded", email="john@example.com", full_name="John Doe"
    )


async def get_current_user(token: str = Depends(oauth2_scheme)):
    user = fake_decode_token(token)
    return user


@app.get("/users/me")
async def read_users_me(current_user: User = Depends(get_current_user)):
    return current_user

注入当前用户

因此现在我们可以在路径操作中使用 get_current_user 作为 Depends 了:

from typing import Optional

from fastapi import Depends, FastAPI
from fastapi.security import OAuth2PasswordBearer
from pydantic import BaseModel

app = FastAPI()

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")


class User(BaseModel):
    username: str
    email: Optional[str] = None
    full_name: Optional[str] = None
    disabled: Optional[bool] = None


def fake_decode_token(token):
    return User(
        username=token + "fakedecoded", email="john@example.com", full_name="John Doe"
    )


async def get_current_user(token: str = Depends(oauth2_scheme)):
    user = fake_decode_token(token)
    return user


@app.get("/users/me")
async def read_users_me(current_user: User = Depends(get_current_user)):
    return current_user

注意我们将 current_user 的类型声明为 Pydantic 模型 User。

这将帮助我们在函数内部使用所有的代码补全和类型检查。

Tip

你可能还记得请求体也是使用 Pydantic 模型来声明的。

在这里 FastAPI 不会搞混,因为你正在使用的是 Depends。

Check

这种依赖系统的设计方式使我们可以拥有不同的依赖项(不同的「可依赖类型」),并且它们都返回一个 User 模型。

我们并未被局限于只能有一个返回该类型数据的依赖项。

其他模型

现在你可以直接在路径操作函数中获取当前用户,并使用 Depends 在依赖注入级别处理安全性机制。

你可以使用任何模型或数据来满足安全性要求(在这个示例中,使用的是 Pydantic 模型 User)。

但是你并未被限制只能使用某些特定的数据模型,类或类型。

你想要在模型中使用 id 和 email 而不使用任何的 username?当然可以。你可以同样地使用这些工具。

你只想要一个 str?或者仅仅一个 dict?还是直接一个数据库模型类的实例?它们的工作方式都是一样的。

实际上你没有用户登录到你的应用程序,而是只拥有访问令牌的机器人,程序或其他系统?再一次,它们的工作方式也是一样的。

尽管去使用你的应用程序所需要的任何模型,任何类,任何数据库。FastAPI 通过依赖项注入系统都帮你搞定。

代码体积

这个示例似乎看起来很冗长。考虑到我们在同一文件中混合了安全性,数据模型工具函数和路径操作等代码。

但关键的是。

安全性和依赖项注入内容只需要编写一次。

你可以根据需要使其变得很复杂。而且只需要在一个地方写一次。但仍然具备所有的灵活性。

但是,你可以有无数个使用同一安全系统的端点(路径操作)。

所有(或所需的任何部分)的端点,都可以利用对这些或你创建的其他依赖项进行复用所带来的优势。

所有的这无数个路径操作甚至可以小到只需 3 行代码:

from typing import Optional

from fastapi import Depends, FastAPI
from fastapi.security import OAuth2PasswordBearer
from pydantic import BaseModel

app = FastAPI()

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")


class User(BaseModel):
    username: str
    email: Optional[str] = None
    full_name: Optional[str] = None
    disabled: Optional[bool] = None


def fake_decode_token(token):
    return User(
        username=token + "fakedecoded", email="john@example.com", full_name="John Doe"
    )


async def get_current_user(token: str = Depends(oauth2_scheme)):
    user = fake_decode_token(token)
    return user


@app.get("/users/me")
async def read_users_me(current_user: User = Depends(get_current_user)):
    return current_user

总结

现在你可以直接在路径操作函数中获取当前用户。

我们已经进行到一半了。

我们只需要再为用户/客户端添加一个真正发送 username 和 password 的路径操作。

这些内容在下一章节。


FastAPI教程 安全性 - 第一步
FastAPI教程 使用密码和 Bearer 的简单 OAuth2
温馨提示
下载编程狮App,免费阅读超1000+编程语言教程
取消
确定
目录

FastAPI 用户指南

关闭

MIP.setData({ 'pageTheme' : getCookie('pageTheme') || {'day':true, 'night':false}, 'pageFontSize' : getCookie('pageFontSize') || 20 }); MIP.watch('pageTheme', function(newValue){ setCookie('pageTheme', JSON.stringify(newValue)) }); MIP.watch('pageFontSize', function(newValue){ setCookie('pageFontSize', newValue) }); function setCookie(name, value){ var days = 1; var exp = new Date(); exp.setTime(exp.getTime() + days*24*60*60*1000); document.cookie = name + '=' + value + ';expires=' + exp.toUTCString(); } function getCookie(name){ var reg = new RegExp('(^| )' + name + '=([^;]*)(;|$)'); return document.cookie.match(reg) ? JSON.parse(document.cookie.match(reg)[2]) : null; }