云计算百科
云计算领域专业知识百科平台

使用 django-oauth-toolkit 3.2.0 构建 Django OAuth2 与 OpenID Connect 授权服务器:从最小配置到 DRF 集成实战指南

【免费下载链接】context-hub

项目地址:
https://gitcode.com/gh_mirrors/co/context-hub

点击查看 免费下载

本篇指南以 Context Hub 维护的 django-oauth-toolkit 文档 为骨架,系统讲解如何把一个 Django 项目改造成 OAuth 2.0 授权服务器(Authorization Server):覆盖最小化配置、客户端注册、授权码 + PKCE 流程、Django REST Framework 鉴权、OpenID Connect 扩展、分离式资源服务器模式,以及从 3.0.0 到 3.2.0 的升级要点。读完本文,你将能够在自己的 Django 项目中独立搭建并运维一个支持授权码、刷新令牌与 OIDC 的授权服务,并安全地保护第一方与第三方客户端访问的 REST API。

一、django-oauth-toolkit 是什么

django-oauth-toolkit(下文简称 DOT)是一个 Python 包,作用是把一个 Django 项目变成 OAuth 2.0 授权服务器。它提供的能力包括:

  • 授权(authorization)流程处理
  • 访问令牌(access token)签发与校验
  • 令牌撤销(revocation)
  • 令牌 introspection(内省校验)
  • 客户端应用(Application)管理
  • Django REST framework(DRF)官方集成
  • 可选的 OpenID Connect(OIDC)支持

它的典型使用场景是:你的 Django 应用需要为第一方或第三方客户端签发并校验 OAuth 令牌,例如自建的移动端 App、SPA、命令行工具或第三方合作伙伴应用需要访问你服务的受保护资源。

需要特别强调的是它的边界:DOT 是一个授权服务器工具包(authorization server toolkit),不是社交登录客户端库。不要用它来做"用 Google/GitHub 账号登录我的网站"这类需求——那是 OAuth 2.0 客户端(social login / third-party client)的工作,应当交给专门的客户端库。

在 Context Hub 中,这份文档是 django 作者目录下的一个多语言文档条目(Python 变体),其 YAML frontmatter 标注了 name: oauth-toolkit、languages: "python"、versions: "3.2.0"、source: maintainer,并带有 django,oauth2,openid-connect,drf,authentication,authorization 标签,供 Agent 通过 chub 检索获取(详见 docs/content-guide.md 对 DOC.md 结构的约定)。

二、版本上下文与兼容性

  • 生态:pypi
  • 包名:django-oauth-toolkit
  • 本文覆盖版本:3.2.0
  • 文档修订:revision: 1,更新于 2026-03-12

关于兼容性,官方文档的 3.2.0 快照给出的支持范围是:Python 3.10 至 3.14、Django 4.2 至 6.0、oauthlib>=3.2.2。需要注意的是,上游各信息面之间存在轻微不一致:PyPI 项目页的部分分区仍显示旧的依赖说明与分类器文本。因此在做升级决策时,应以官方文档根页面 + changelog 为准,而不是依赖 PyPI 页面上可能过时的描述文字。

三、安装

最小安装只需 pip:

pip install django-oauth-toolkit==3.2.0

如果你的目的是保护 Django REST framework 的 API,需要一并安装 DRF:

pip install django-oauth-toolkit==3.2.0 djangorestframework

安装完成后,把 oauth2_provider 加入 INSTALLED_APPS 并执行迁移即可(见下一节)。

四、最小化授权服务器配置

1. 修改 settings.py

添加应用、定义 scope、保持 PKCE 开启:

# settings.py

INSTALLED_APPS = [
# Django apps…
"oauth2_provider",
]

OAUTH2_PROVIDER = {
"SCOPES": {
"read": "Read access",
"write": "Write access",
},
"PKCE_REQUIRED": True,
}

这里有两个关键点:

  • SCOPES 定义了你的令牌可以请求的所有 scope。客户端申请令牌时必须在此集合范围内取值,未声明的 scope 不会被签发。
  • PKCE_REQUIRED 默认即为 True(下文设置一节会再次强调),意味着所有授权码流程默认强制要求 PKCE 证明密钥交换。

2. 暴露 OAuth 端点

DOT 自带一套完整的路由,通过 include 挂载即可,习惯上挂载在 /o/ 前缀下:

# urls.py
from django.urls import include, path
from oauth2_provider import urls as oauth2_urls

urlpatterns = [
path("o/", include(oauth2_urls)),
]

3. 执行迁移并创建管理员

python manage.py migrate
python manage.py createsuperuser

迁移会创建 DOT 的模型表(oauth2_provider_application、oauth2_provider_accesstoken、oauth2_provider_refreshtoken、oauth2_provider_grant 等)。随后在 Django admin 的 Applications 菜单下即可创建客户端应用。

五、注册客户端应用

通过 Django admin 注册

对于大多数浏览器、SPA 和移动端客户端,创建应用时的关键选项如下:

配置项建议取值说明
Grant type Authorization code 最通用、最安全的授权码授权类型
Client type Public(SPA/原生应用);Confidential(服务端应用) 决定能否安全持有 client secret
Redirect URIs 精确的回调 URI 必须是完全匹配的 URI,不要随意写通配符
Allowed origins 浏览器端客户端所需的跨域来源 浏览器端客户端从另一个 origin 调用令牌端点时需要
PKCE 默认启用 新版默认要求 PKCE

对于 Confidential(机密)客户端,需要注意:DOT 在新版本中会在保存时对客户端密钥做哈希处理,因此如果你需要在服务器之外使用明文密钥,必须在创建时立即复制保存——之后无法再从 Django admin 中恢复明文。

通过管理命令程序化创建

DOT 内置了 createapplication 管理命令,适合脚本化、可重复的创建场景:

python manage.py createapplication \\
"web-app" \\
admin \\
authorization-code \\
confidential \\
"https://app.example.com/callback"

参数依次为:应用名称、用户(此处为 admin)、授权类型、客户端类型、重定向 URI。创建完成后,从数据库或命令输出中取出 client_id(以及机密客户端的 client_secret,若需要外部使用须及时保存)。

六、授权码流程(Authorization Code Flow)

流程概览

最常见的 OAuth 2.0 授权码流程包含四步:

  • 将用户重定向到 /o/authorize/;
  • 在你的重定向 URI 上收到授权码(authorization code);
  • 用授权码在 /o/token/ 换取访问令牌;
  • 将 Bearer 令牌发送到受保护的 API。
  • 构造授权 URL(公开 PKCE 客户端)

    from urllib.parse import urlencode

    params = urlencode(
    {
    "client_id": "YOUR_CLIENT_ID",
    "response_type": "code",
    "redirect_uri": "https://app.example.com/callback",
    "scope": "read write",
    "code_challenge": "BASE64URL_SHA256_CODE_VERIFIER",
    "code_challenge_method": "S256",
    }
    )

    authorize_url = f"https://auth.example.com/o/authorize/?{params}"

    其中 code_challenge 是原始 code_verifier 经过 SHA-256 哈希后再进行 base64url 编码的结果,code_challenge_method 固定为 S256。这是 PKCE 的核心:授权请求阶段只提交哈希后的挑战值,令牌交换阶段才提交原始验证值,从而避免授权码被截获后直接冒用。

    兑换令牌(公开 PKCE 客户端)

    import requests

    response = requests.post(
    "https://auth.example.com/o/token/",
    data={
    "grant_type": "authorization_code",
    "client_id": "YOUR_CLIENT_ID",
    "code": "CODE_FROM_CALLBACK",
    "redirect_uri": "https://app.example.com/callback",
    "code_verifier": "ORIGINAL_CODE_VERIFIER",
    },
    timeout=30,
    )
    response.raise_for_status()
    token = response.json()

    返回的 token 中通常包含 access_token、token_type: "Bearer"、expires_in、scope,以及(如果申请了 offline_access 或配置允许时)refresh_token。

    机密客户端如何交换

    对于 Confidential(机密)客户端,令牌交换请求应使用 HTTP Basic 认证携带 client_id 与 client_secret 对授权服务器进行身份认证,而不是把应用当作纯 PKCE 公开客户端来处理。也就是说:机密客户端同样可以配合 PKCE(推荐),但身份凭证必须正确传递。

    七、保护 Django REST Framework API

    DOT 与 DRF 的集成通过 oauth2_provider.contrib.rest_framework 模块实现,核心是 OAuth2Authentication 认证类和一组 scope 感知的权限类。

    全局配置认证类

    # settings.py
    REST_FRAMEWORK = {
    "DEFAULT_AUTHENTICATION_CLASSES": (
    "oauth2_provider.contrib.rest_framework.OAuth2Authentication",
    ),
    }

    在视图中组合认证与权限

    # views.py
    from oauth2_provider.contrib.rest_framework import (
    OAuth2Authentication,
    TokenHasReadWriteScope,
    )
    from rest_framework.response import Response
    from rest_framework.views import APIView

    class DocumentView(APIView):
    authentication_classes = [OAuth2Authentication]
    permission_classes = [TokenHasReadWriteScope]
    required_scopes = ["documents"]

    def get(self, request):
    return Response({"ok": True})

    权限语义说明:

    • TokenHasReadWriteScope 会根据 HTTP 方法自动要求已配置的 read 或 write scope(读取类方法要求 read,写入类方法要求 write),同时还会校验你在视图上声明的 required_scopes。它适合"读操作/写操作"这类资源级权限模型。
    • 当你需要精确的 scope 匹配、不希望引入读/写语义时,使用 TokenHasScope:它只检查令牌是否包含视图声明的 scope。

    两种权限类都基于令牌中携带的 scope 集合做校验:令牌签发时声明了什么 scope,访问 API 时就被允许调用什么范围的操作。

    八、常用设置详解(Settings That Usually Matter)

    以下是生产环境中通常需要关注的 OAUTH2_PROVIDER 设置项:

    设置项默认值 / 建议说明
    SCOPES 必配 定义你的令牌可能请求的每一个 scope,未在此声明的 scope 不会被签发
    DEFAULT_SCOPES __all__ 若不想默认授予全部 scope,请显式收窄默认值
    PKCE_REQUIRED True 默认开启,保持开启;仅当你有无法支持 PKCE 的受控遗留客户端时才考虑关闭
    ALLOWED_REDIRECT_URI_SCHEMES 默认包含 http/https 等 生产环境设置为 ["https"];原生应用的回环(loopback)http 重定向可接受
    REFRESH_TOKEN_REUSE_PROTECTION 关闭 配合轮换的刷新令牌使用,检测到重用即撤销相关会话
    REFRESH_TOKEN_EXPIRE_SECONDS 见官方默认 控制清理资格,其本身并不会让刷新令牌在校验时过期
    CLEAR_EXPIRED_TOKENS_BATCH_SIZE — 调整大批量过期令牌清理作业的批次大小
    CLEAR_EXPIRED_TOKENS_BATCH_INTERVAL — 调整清理批次间的执行间隔
    ALLOW_URI_WILDCARDS False(3.1.0 新增) 允许重定向/origin 通配符;生产环境避免开启,除非你完全理解重定向-origin 风险

    其中两个最容易误解的设置需要重点解释:

  • REFRESH_TOKEN_EXPIRE_SECONDS 不等于刷新令牌自动过期校验。官方文档明确指出:该参数只控制过期刷新令牌被 cleartokens 清理的资格判定,刷新令牌本身的校验并不会因此自动过期。这意味着如果你签发了刷新令牌,必须定期执行清理,否则过期刷新令牌会在数据库中长期累积。

  • ALLOW_URI_WILDCARDS 是安全敏感的逃生舱。它允许重定向 URI 与 allowed origins 中的通配符匹配,但也可能扩大重定向攻击面,应当只作为受控预览环境下的最后手段。

  • 配套的清理命令:cleartokens

    DOT 提供 cleartokens 管理命令用于清理过期令牌:

    python manage.py cleartokens

    如果你签发了刷新令牌,应当通过 cron / Celery beat 等方式定期调度该命令。不规律清理的后果是过期刷新令牌在数据库中的持续累积。再次强调:REFRESH_TOKEN_EXPIRE_SECONDS 单独使用并不会让刷新令牌校验自行过期。

    九、OpenID Connect 设置

    OIDC 是可选能力,默认关闭。开启后,DOT 可以在 OAuth 2.0 基础上签发 ID Token(JWT),用于身份认证(Authentication)场景。签名算法优先选择 RS256(非对称)。

    生成 RSA 私钥

    openssl genrsa -out oidc.key 4096

    启用 OIDC 并配置密钥

    # settings.py
    import os

    OAUTH2_PROVIDER = {
    "OIDC_ENABLED": True,
    "OIDC_RSA_PRIVATE_KEY": os.environ["OIDC_RSA_PRIVATE_KEY"],
    "SCOPES": {
    "openid": "OpenID Connect scope",
    "profile": "Profile access",
    "email": "Email access",
    },
    }

    注意:OIDC 需要 openid scope 出现在 SCOPES 中,客户端请求时也必须携带 openid scope 才会签发 ID Token。密钥建议从环境变量读取,而不是硬编码进配置文件。

    重要的 OIDC 约束

    • 私钥不要进入版本控制:OIDC_RSA_PRIVATE_KEY 应来自安全的密钥管理系统或环境变量。
    • 自定义 server class 的继承约束:如果你已经自定义了 OAUTH2_SERVER_CLASS,那么启用 OIDC 时,该类必须派生自 oauthlib.openid.Server,否则 OIDC 能力不生效。
    • HS256 的局限:HS256 使用应用客户端密钥进行签名,实现更简单,但灵活性差,且不适用于公开客户端(Public clients)以及 implicit/hybrid 流程。因此优先使用 RS256。
    • 密钥轮换:进行 RSA 密钥轮换时,使用 OIDC_RSA_PRIVATE_KEYS_INACTIVE 配置"非活跃旧密钥"列表来支持旧密钥的平滑过渡,而不是突然替换 OIDC_RSA_PRIVATE_KEY,避免已签发的 ID Token 瞬间全部失效。

    十、分离资源服务器模式(Separate Resource Server Pattern)

    当你的 API 服务与授权服务器是两个独立部署的服务时,DOT 支持令牌 introspection(内省)机制,让资源服务器无需共享数据库即可校验令牌。

    授权服务器侧

    • 包含 introspection 端点:挂载在 /o/introspect/ 下(DOT 路由默认已提供);
    • 添加一个 introspection scope;
    • 为资源服务器签发一个可用于 introspection 的专用令牌(通常是 confidential 客户端令牌)。

    资源服务器侧

    在资源服务器的 OAUTH2_PROVIDER 中配置:

    • RESOURCE_SERVER_INTROSPECTION_URL:指向授权服务器的 introspection 端点;
    • 二选一设置凭证:
      • RESOURCE_SERVER_AUTH_TOKEN:固定 Bearer 令牌;或
      • RESOURCE_SERVER_INTROSPECTION_CREDENTIALS:client_id 与 client_secret 凭证。

    何时使用

    仅当你确实拆分部署了授权服务器与资源服务器时才使用 introspection。对于单个 Django 应用(授权与资源同体),使用标准的本地令牌校验(即前一节的 DRF OAuth2Authentication 直接校验签名/数据库中的令牌)更加简单、开销更低、也更可靠。introspection 模式引入了额外的网络往返与依赖,不应被当作默认方案。

    十一、常见陷阱(Common Pitfalls)

    结合 DOT 3.2.0 的官方说明,以下是最容易踩坑的点:

  • 定位错误:DOT 是授权服务器工具包,不是第三方 OAuth 客户端或社交登录包。需求选型时先分清你是"发令牌的一方"还是"消费别人令牌的一方"。
  • 依赖过时教程:较老的博客文章常展示过时的配置方式。请以当前 3.2.0 的官方文档为准来配置 URL 挂载(/o/ 前缀)与设置项名称。
  • 公开客户端遗漏 PKCE 参数:公开客户端如果漏传 code_challenge / code_verifier,授权码交换会直接失败,因为 PKCE_REQUIRED 默认开启。
  • 明文密钥不可恢复:开启哈希后,客户端明文 secret 在保存后无法从 admin 恢复。创建 confidential 客户端时务必当场复制。
  • 刷新令牌清理误解:REFRESH_TOKEN_EXPIRE_SECONDS 不会在校验时自动使刷新令牌失效,它主要驱动 cleartokens 清理;除非你自定义校验逻辑,否则过期刷新令牌依然可能被用于换取新令牌,必须配合轮换与重用保护。
  • 通配符逃生舱:ALLOW_URI_WILDCARDS 是安全敏感配置,应作为受控预览环境的最后手段,生产环境默认保持关闭。
  • 3.0.0 升级的隐藏成本:从 3.0.0 之前的版本升级时,若你使用了可替换的 DOT 模型(swappable models),或代码假设令牌模型主键名为 id,需要格外小心迁移。
  • 十二、版本敏感信息(Version-Sensitive Notes)

    • 3.2.0:新增**设备授权授权类型(device authorization grant)**支持;新增对 Django 5.2 与 Python 3.14 的支持。
    • 3.1.0:通过 ALLOW_URI_WILDCARDS 新增重定向/origin 通配符支持;修复了若干迁移与 introspection 问题。
    • 3.0.1:修复了数据库中已存在存量访问令牌时的迁移错误。
    • 3.0.0(重要的破坏性分界线):
      • 升级后必须执行 python manage.py migrate;
      • 更新自定义的 swappable 模型并(如有需要)生成对应迁移;
      • Django 低于 4.2 的版本不再受支持;
      • 访问令牌存储改为 TextField + token_checksum(令牌原文不再直接可查,改为校验和比对);
      • 引入 REFRESH_TOKEN_REUSE_PROTECTION 作为安全控制;
      • 最低 oauthlib 版本要求为 3.2.2+。

    十三、在 Context Hub 中获取与维护本文档

    这份指南在仓库中的位置是 content/django/docs/oauth-toolkit/python/DOC.md,属于 Context Hub 的 django 作者目录下 oauth-toolkit 条目的 Python 语言变体。按照 docs/content-guide.md 的约定,DOC.md 使用 YAML frontmatter 声明 name、description、metadata.languages、metadata.versions、metadata.revision、metadata.updated-on、metadata.source 等字段,其中 source: maintainer 表示该条目由 Context Hub 维护团队编写,属于可信来源;versions: "3.2.0" 与 PyPI 上的包版本对齐,便于 Agent 从 requirements.txt 探测到依赖版本后精确匹配文档。

    如果你的 Coding Agent 需要编写或校验使用 django-oauth-toolkit 的代码,可以按 cli/skills/get-api-docs/SKILL.md 的流程,先运行 chub –help 获取最新指令,再用 chub search "django oauth toolkit" 找到条目,最后 chub get django/oauth-toolkit –lang py 拉取本文档内容;若在实战中发现文档未覆盖的坑(例如某个 grant type 的边界行为),还可以用 chub annotate 记录本地笔记,并用 chub feedback 反馈给维护者,推动文档持续改进(详见 docs/feedback-and-annotations.md 与 docs/features/agent-annotations.md)。

    需要说明的是:本文对兼容性、默认值等细节的表述均以 DOT 3.2.0 官方文档快照为准(本仓库该条目即其忠实整理版);如果你正在使用的版本不同(如仍在 2.x),请以对应版本文档和 changelog 为准,尤其关注 3.0.0 的破坏性变更清单。

    赞

    分享

    【免费下载链接】context-hub

    项目地址:
    https://gitcode.com/gh_mirrors/co/context-hub

    点击查看 免费下载

    上一篇:
    Kubernetes服务安全暴露实战:Cloudflare Tunnel控制器完整指南

    下一篇:
    Mongoose OS I2C通信实战:传感器数据采集与处理

    创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » 使用 django-oauth-toolkit 3.2.0 构建 Django OAuth2 与 OpenID Connect 授权服务器:从最小配置到 DRF 集成实战指南
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!