0

0

具有依赖注入的 FastAPI 身份验证

DDD

DDD

发布时间:2024-09-24 12:51:01

|

891人浏览过

|

来源于dev.to

转载

具有依赖注入的 fastapi 身份验证

fastapi 是一个用于在 python 中构建 api 的现代 web 框架。它是我个人最喜欢的 web 框架之一,因为它内置了对 openapi 规范的支持(这意味着您可以编写后端代码并从中生成所有内容),并且它支持依赖注入

在这篇文章中,我们将简要介绍一下 fastapi 的 depends 是如何工作的。然后我们将了解为什么它如此适用于身份验证和授权。我们还将它与中间件进行对比,中间件是身份验证的另一个常见选项。最后,我们将了解 fastapi 中一些更高级的授权模式。

什么是依赖注入?

fastapi 更强大的功能之一是它对 依赖注入 的一流支持。我们有一个更长的指南这里,但让我们看一个如何使用它的快速示例。

假设我们正在构建一个分页 api。每个api调用可以包括page_number和page_size。现在,我们可以创建一个 api 并直接传入这些参数:

@app.get("/things/")
async def fetch_things(page_number: int = 0, page_size: int = 100):
    return db.fetch_things(page_number, page_size)

但是,我们可能想添加一些验证逻辑,这样就没有人要求 page_number -1 或 page_size 10,000,000。

@app.get("/things/")
async def fetch_things(page_number: int = 0, page_size: int = 100):
    if page_number < 0:
        raise httpexception(status_code=400, detail="invalid page number")
    elif page_size <= 0:
        raise httpexception(status_code=400, detail="invalid page size")
    elif page_size > 100:
        raise httpexception(status_code=400, detail="page size can be at most 100")
    return db.fetch_things(page_number, page_size)

这……很好,但如果我们有 10 个 api 或 100 个 api 都需要相同的分页参数,那就有点乏味了。这就是依赖注入的用武之地 - 我们可以将所有这些逻辑移至一个函数中,并将该函数注入到我们的 api 中:

async def paging_params_dep(page_number: int = 0, page_size: int = 100):
    if page_number < 0:
        raise httpexception(status_code=400, detail="invalid page number")
    elif page_size <= 0:
        raise httpexception(status_code=400, detail="invalid page size")
    elif page_size > 100:
        raise httpexception(status_code=400, detail="page size can be at most 100")
    return pagingparams(page_number, page_size)

@app.get("/things/")
async def fetch_things(paging_params: pagingparams = depends(paging_params_dep)):
    return db.fetch_things(paging_params)

@app.get("/other_things/")
async def fetch_other_things(paging_params: pagingparams = depends(paging_params_dep)):
    return db.fetch_other_things(paging_params)

这有一些不错的好处:

  • 每条采用 pagingparams 的路由都会自动验证并具有默认值。

  • 它比每条路由的第一行是 validate_paging_params(page_number, page_size)

  • 更简洁,更容易出错
  • 这仍然适用于 fastapi 的 openapi 支持 - 这些参数将显示在您的 openapi 规范中。

这与身份验证有什么关系?

事实证明,这也是一种建模身份验证的好方法!想象一下你有一个像这样的函数:

async def validate_token(token: str):
    try:
        # this could be jwt validation, looking up a session token in the db, etc.
        return await get_user_for_token(token)
    except:
        return none

要将其连接到 api 路由,我们需要做的就是将其包装在依赖项中:

async def require_valid_token_dep(req: request):
    # this could also be a cookie, x-api-key header, etc.
    token = req.headers["authorization"]
    user = await validate_token(token)
    if user == none:
        raise httpexception(status_code=401, detail="unauthorized")
    return user

然后我们所有受保护的路由都可以添加此依赖项:

@app.get("/protected")
async def do_secret_things(user: user = depends(require_valid_token_dep)):
    # do something with the user

如果用户提供了有效的令牌,则该路由将运行并设置用户。否则,将返回 401。

注意:openapi/swagger 确实对指定身份验证令牌具有一流的支持,但您必须使用其中一个专用类。您可以使用 fastapi.security 中的 httpbearer(auto_error=false) 来代替 req.headers["authorization"],它会返回 httpauthorizationcredentials。

中间件与 depends for auth

fastapi 与大多数框架一样,有一个中间件 的概念。您的中间件可以包含将在请求之前和之后运行的代码。它可以在请求到达您的路由之前修改请求,也可以在响应返回给用户之前修改响应。

在许多其他框架中,中间件是进行身份验证检查的非常常见的地方。然而,这通常是因为中间件还负责将用户“注入”到路由中。例如,express 中的常见模式是执行以下操作:

app.get("/protected", authmiddleware, (req, res) => {
    // req.user is set by the middleware
    // as there's no good way to pass in extra information into this route,
    // outside of the request
});

由于fastapi具有内置的注入概念,因此您可能根本不需要使用中间件。如果您需要定期“刷新”您的身份验证令牌(以使其保持活动状态)并将响应设置为 cookie,我会考虑使用中间件。

MusicAI
MusicAI

AI音乐生成工具

下载

在这种情况下,您需要使用 request.state 将信息从中间件传递到路由(如果您愿意,您可以使用依赖项来验证 request.state)。

否则,我会坚持使用 depends,因为用户将被直接注入到您的路由中,而不需要通过 request.state。

授权 - 多租户、角色和权限

如果我们应用迄今为止所学到的一切,添加多租户、角色或权限可能会非常简单。假设我们为每个客户都有一个唯一的子域,我们可以为该子域建立依赖关系:

async def tenant_by_subdomain_dep(request: request) -> optional[str]:
    # first we get the subdomain from the host header
    host = request.headers.get("host", "")
    parts = host.split(".")
    if len(parts) <= 2:
        raise httpexception(status_code=404, detail="not found")
    subdomain = parts[0]

    # then we lookup the tenant by subdomain
    tenant = await lookup_tenant_for_subdomain(subdomain)
    if tenant == none:
        raise httpexception(status_code=404, detail="not found")
    return tenant

我们可以将这个想法与之前的想法结合起来,制作一个新的“多租户”依赖:

async def get_user_and_tenant_for_token(
    user: user = depends(require_valid_token_dep),
    tenant: tenant = depends(tenant_by_subdomain_dep),
) -> userandtenant:
    is_user_in_tenant = await check_user_is_in_tenant(tenant, user)
    if is_user_in_tenant:
        return userandtenant(user, tenant)
    raise httpexception(status_code=403, detail="forbidden")

然后我们可以将此依赖项注入到我们的路由中:

@app.get("/protected")
async def do_secret_things(user_and_tenant: userandtenant = depends(get_user_and_tenant_for_token)):
    # do something with the user and tenant

这最终会做一些主要的事情:

  • 检查用户是否拥有有效令牌

  • 检查用户是否正在向有效的子域发出请求

  • 检查用户是否应该有权访问该子域

如果不满足任何这些不变量 - 将返回错误并且我们的路线将永远不会运行。我们可以扩展它以包括其他内容,例如角色和权限 (rbac) 或确保用户具有特定的属性集(有效付费订阅与无有效订阅)。

propelauth

在 propelauth,我们是 fastapi 的忠实粉丝。我们有一个 fastapi 库,使您能够快速设置身份验证和授权 - 包括 sso、企业 sso / saml、scim 配置等。

这一切都与您在上面看到的依赖项一起工作,例如:

@app.get("/")
async def root(current_user: User = Depends(auth.require_user)):
    return {"message": f"Hello {current_user.user_id}"}

您可以在这里了解更多信息。

总结

  • fastapi 的依赖注入 提供了一种强大的方法来处理 web 应用程序中的身份验证和授权。

  • depends 功能允许使用干净、可重用的代码来验证令牌、检查用户权限和处理多租户。

  • 与中间件相比,使用依赖项进行身份验证提供了更大的灵活性以及与路由功能的直接集成。

  • 复杂的授权场景,例如多租户和基于角色的访问控制可以使用嵌套依赖项有效地实现。

  • propelauth 提供了一个 fastapi 库,可以简化高级身份验证和授权功能的实现。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
什么是中间件
什么是中间件

中间件是一种软件组件,充当不兼容组件之间的桥梁,提供额外服务,例如集成异构系统、提供常用服务、提高应用程序性能,以及简化应用程序开发。想了解更多中间件的相关内容,可以阅读本专题下面的文章。

182

2024.05.11

Golang 中间件开发与微服务架构
Golang 中间件开发与微服务架构

本专题系统讲解 Golang 在微服务架构中的中间件开发,包括日志处理、限流与熔断、认证与授权、服务监控、API 网关设计等常见中间件功能的实现。通过实战项目,帮助开发者理解如何使用 Go 编写高效、可扩展的中间件组件,并在微服务环境中进行灵活部署与管理。

225

2025.12.18

Node.js后端开发与Express框架实践
Node.js后端开发与Express框架实践

本专题针对初中级 Node.js 开发者,系统讲解如何使用 Express 框架搭建高性能后端服务。内容包括路由设计、中间件开发、数据库集成、API 安全与异常处理,以及 RESTful API 的设计与优化。通过实际项目演示,帮助开发者快速掌握 Node.js 后端开发流程。

403

2026.02.10

Python FastAPI异步API开发_Python怎么用FastAPI构建异步API
Python FastAPI异步API开发_Python怎么用FastAPI构建异步API

Python FastAPI 异步开发利用 async/await 关键字,通过定义异步视图函数、使用异步数据库库 (如 databases)、异步 HTTP 客户端 (如 httpx),并结合后台任务队列(如 Celery)和异步依赖项,实现高效的 I/O 密集型 API,显著提升吞吐量和响应速度,尤其适用于处理数据库查询、网络请求等耗时操作,无需阻塞主线程。

28

2025.12.22

Python 微服务架构与 FastAPI 框架
Python 微服务架构与 FastAPI 框架

本专题系统讲解 Python 微服务架构设计与 FastAPI 框架应用,涵盖 FastAPI 的快速开发、路由与依赖注入、数据模型验证、API 文档自动生成、OAuth2 与 JWT 身份验证、异步支持、部署与扩展等。通过实际案例,帮助学习者掌握 使用 FastAPI 构建高效、可扩展的微服务应用,提高服务响应速度与系统可维护性。

251

2026.02.06

cookie
cookie

Cookie 是一种在用户计算机上存储小型文本文件的技术,用于在用户与网站进行交互时收集和存储有关用户的信息。当用户访问一个网站时,网站会将一个包含特定信息的 Cookie 文件发送到用户的浏览器,浏览器会将该 Cookie 存储在用户的计算机上。之后,当用户再次访问该网站时,浏览器会向服务器发送 Cookie,服务器可以根据 Cookie 中的信息来识别用户、跟踪用户行为等。

6498

2023.06.30

document.cookie获取不到怎么解决
document.cookie获取不到怎么解决

document.cookie获取不到的解决办法:1、浏览器的隐私设置;2、Same-origin policy;3、HTTPOnly Cookie;4、JavaScript代码错误;5、Cookie不存在或过期等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

368

2023.11.23

阻止所有cookie什么意思
阻止所有cookie什么意思

阻止所有cookie意味着在浏览器中禁止接受和存储网站发送的cookie。阻止所有cookie可能会影响许多网站的使用体验,因为许多网站使用cookie来提供个性化服务、存储用户信息或跟踪用户行为。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

443

2024.02.23

JavaScript浏览器渲染机制与前端性能优化实践
JavaScript浏览器渲染机制与前端性能优化实践

本专题围绕 JavaScript 在浏览器中的执行与渲染机制展开,系统讲解 DOM 构建、CSSOM 解析、重排与重绘原理,以及关键渲染路径优化方法。内容涵盖事件循环机制、异步任务调度、资源加载优化、代码拆分与懒加载等性能优化策略。通过真实前端项目案例,帮助开发者理解浏览器底层工作原理,并掌握提升网页加载速度与交互体验的实用技巧。

23

2026.03.06

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
最新Python教程 从入门到精通
最新Python教程 从入门到精通

共4课时 | 22.5万人学习

Django 教程
Django 教程

共28课时 | 4.8万人学习

SciPy 教程
SciPy 教程

共10课时 | 1.8万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号