Skip to main content

子平台接入 AuthHub 的官方 Python SDK:登录、运行时鉴权一站直达。

Project description

authhub-rbac-sdk

子平台(cortexa / athanor / …)接入 AuthHub 的官方 RBAC SDK。

PyPI: https://pypi.org/project/authhub-rbac-sdk/

完整 API 参考(所有类、方法、参数、返回值、Django/FastAPI 集成):docs/reference/authhub-sdk.md

核心约束:子平台只调 AuthHub,绝不直接连 PhilVault;登录、token 刷新、 每次请求的鉴权决策都走 AuthHub HTTP API(/api/v2/auth/*/api/v2/sdk/*)。 路由 → 资源/动作 的映射由 AuthHub 服务端匹配,SDK 端无感。

与历史 authz/ 的关系

旧的 authz/ 是 Vortek/湍流版权的 Django 中间件,直接调用 philvault_sdk。 本 SDK 是其替代品:

维度 authz/ (Vortek) authhub_sdk/
通信对象 直连 PhilVault 只调 AuthHub
路由映射匹配 子平台拉 /authz/mapping 本地缓存 AuthHub 服务端匹配
鉴权决策 本地 + PhilVault check 一次 POST /sdk/authorize 拿结论
跨框架 仅 Django Django + FastAPI
Token 缓存 30s 本地缓存 默认无缓存(运行时鉴权链路不缓存)

新接入的子平台只用本包,不要再引入 authz/

安装

从 PyPI 安装:

# 基础安装(只用 AuthhubClient / AsyncAuthhubClient)
pip install authhub-rbac-sdk

# Django 接入(自动带上 Django >=4.2)
pip install "authhub-rbac-sdk[django]"

# FastAPI 接入
pip install "authhub-rbac-sdk[fastapi]"

# Django + FastAPI 都装
pip install "authhub-rbac-sdk[all]"

仓库内开发:

# 基础安装
pip install /path/to/authhub/authhub_sdk

# Django 接入
pip install "authhub-rbac-sdk[django] @ file:///path/to/authhub/authhub_sdk"

# FastAPI 接入
pip install "authhub-rbac-sdk[fastapi] @ file:///path/to/authhub/authhub_sdk"

# 开发依赖(含 pytest)
pip install -e "/path/to/authhub/authhub_sdk[dev]"

依赖:

  • httpx >= 0.27(基础)
  • Python 3.10+
  • Django >=4.2(extra [django]
  • FastAPI >=0.110(extra [fastapi]

包采用 src/ 布局:源码在 authhub_sdk/src/authhub_sdk/,安装后通过 import authhub_sdk 引用,与 Django/FastAPI 上游包不会发生命名冲突。

PyPI 包名是 authhub-rbac-sdk,但 import 路径仍是 authhub_sdk

三件套环境变量

export AUTHHUB_BASE_URL=http://authhub.internal:6001  # 不带 /api/v2
export AUTHHUB_APP_CODE=cortexa
# 可选
export AUTHHUB_TIMEOUT=5
export AUTHHUB_VERIFY_SSL=true
export AUTHHUB_BYPASS_PATHS=/health,/static/,/api/v2/sdk/healthz
# API Key 模式可选
export AUTHHUB_AUTH_MODE=api_key
export AUTHHUB_API_KEY=ahk_xxx

AUTHHUB_BYPASS_PATHS 是逗号分隔的前缀列表,命中后不调 AuthHub。

基础用法:HTTP 客户端

同步

from authhub_sdk import AuthhubClient

with AuthhubClient.from_env() as client:
    # 登录(子平台前端或后端都可发起)
    result = client.login("alice", "User@123456")
    access_token = result["access_token"]

    # 当前用户信息
    me = client.me(access_token)
    print(me.user_id, me.username, me.domain_roles)

    # 每次业务请求前调一次(中间件已自动做了,这里仅演示)
    outcome = client.authorize(
        access_token,
        method="GET",
        path="/api/v1/projects/123",
    )
    if not outcome.allow:
        raise PermissionError(outcome.reason)

异步

from authhub_sdk import AsyncAuthhubClient

async with AsyncAuthhubClient.from_env() as client:
    outcome = await client.authorize(token, method="POST", path="/api/v1/orders")

API Key 模式

API Key 是应用接入凭证,不解析用户、不走用户级 RBAC。一个 Key 可在 AuthHub 管理台绑定多个应用;服务端应用用 AUTHHUB_API_KEY 向 AuthHub 证明「当前 app_code 是否属于该 Key 的绑定范围」。

from authhub_sdk import AuthhubClient

with AuthhubClient.from_env() as client:
    outcome = client.authorize_with_api_key(
        method="GET",
        path="/api/v1/projects",
    )
    if not outcome.allow:
        raise PermissionError(outcome.reason)

Django / FastAPI 中间件使用 API Key 模式时,配置:

export AUTHHUB_AUTH_MODE=api_key
export AUTHHUB_API_KEY=ahk_xxx

此模式下中间件不要求业务请求携带 Authorization: Bearer ...

显式传配置(不走 env):

from authhub_sdk import AuthhubClient
from authhub_sdk.config import AuthhubConfig

cfg = AuthhubConfig(base_url="http://authhub.internal:6001", app_code="cortexa")
client = AuthhubClient(config=cfg)

Django 接入

1. 安装中间件

settings.py

INSTALLED_APPS = [
    # ...
]

MIDDLEWARE = [
    "django.middleware.security.SecurityMiddleware",
    "django.middleware.common.CommonMiddleware",
    "corsheaders.middleware.CorsMiddleware",  # 若用 corsheaders
    "authhub_sdk.django.AuthhubMiddleware",   # ← 放在业务中间件之前
    # ...
]

# 与 from_env 等价;也可以省略改用环境变量
AUTHHUB_SDK = {
    "base_url": "http://authhub.internal:6001",
    "app_code": "cortexa",
    "bypass_paths": ["/health/", "/static/", "/admin/login/"],
}

中间件对每个请求按以下顺序处理:

bypass_paths > X-API-Key > Authorization: Bearer

即使 AUTHHUB_AUTH_MODE=user,只要请求携带 X-API-Key,Django 中间件也会先调用 /api/v2/sdk/api-key/authorize。API Key 未放行且请求 同时携带 Bearer Token 时,再回退到用户 Token 鉴权。

2. 在 view 里拿用户

中间件鉴权通过后会注入:

属性 类型 含义
request.authhub_outcome AuthorizeOutcome 完整鉴权结果
request.authhub_user dict PhilVault /auth/me 返回的用户字典
request.authhub_user_id str 用户 ObjectId
request.authhub_access_token str 透出本次请求的 token
request.auth_type str API Key 放行时为 api_key
request.api_key_source str AuthHub API Key 放行时为 authhub
request.authhub_key_id str AuthHub API Key ID
from django.http import JsonResponse

def get_my_projects(request):
    user_id = request.authhub_user_id
    return JsonResponse({"user_id": user_id})

3. 错误响应

场景 HTTP body
缺/无效 Bearer token 401 {"detail": "Unauthorized: ...", "request_id": "..."}
AuthHub 决策为 deny 403 {"detail": <reason>, "decision": "deny", "mapping": {...}}
AuthHub 不可达 / 5xx 502 {"detail": "Auth backend unavailable"}
CORS preflight (OPTIONS) 不鉴权,直接放行

FastAPI 接入

from fastapi import FastAPI, Depends
from authhub_sdk.fastapi import AuthhubContext, authhub_required

app = FastAPI()
guard = authhub_required()  # 从 AUTHHUB_* env 读配置

@app.get("/api/v1/projects/{project_id}")
async def get_project(
    project_id: str,
    ctx: AuthhubContext = Depends(guard),
):
    return {
        "project_id": project_id,
        "viewer": ctx.user_id,
        "decision": ctx.outcome.decision,
    }

按 view 粒度切换鉴权:把不需要鉴权的 view 不依赖 guard 即可。或者全局挂依赖:

app = FastAPI(dependencies=[Depends(guard)])

错误响应(标准 FastAPI HTTPException):

  • 401 {"detail": "Unauthorized: missing bearer token"}
  • 403 {"detail": "<reason>"}
  • 502 {"detail": "Auth backend unavailable"}

登录链路(前端直调 AuthHub)

┌──────────┐                ┌──────────┐                ┌────────────┐
│ 子平台前端 │ ──login()──▶ │ AuthHub  │ ──login()────▶ │ PhilVault  │
│          │ ◀─token────── │          │ ◀─token─────── │            │
└──────────┘                └──────────┘                └────────────┘
     │
     │  Authorization: Bearer <token>
     ▼
┌──────────┐                ┌──────────┐                ┌────────────┐
│ 子平台后端 │ ◀──HTTP────── │ 中间件   │ ─authorize()─▶│  AuthHub   │
│ (view)   │                │ (SDK)    │                │ /sdk/...   │
└──────────┘                └──────────┘                └────────────┘
  • 用户在子平台前端直接 POST /api/v2/auth/loginAuthHub(不经过子平台后端)
  • 拿到 access_token 后所有业务请求都带 Authorization: Bearer <token>
  • 子平台后端的中间件收到请求 → 调 POST /api/v2/sdk/authorize → 按 allow 字段放/拒
  • token 过期:前端用 refresh_token/api/v2/auth/refresh 拿新 access_token

异常体系

from authhub_sdk import AuthhubError, AuthhubHTTPError, AuthhubUnauthorized

try:
    client.authorize(token, method="GET", path="/api/v1/items")
except AuthhubUnauthorized:
    # 401:token 无效或过期。让用户重新登录
    ...
except AuthhubHTTPError as exc:
    # 其它 4xx/5xx。exc.status_code / exc.payload / exc.request_id
    ...
except AuthhubError:
    # 网络层(超时、DNS、连接拒绝)
    ...

继承关系:

Exception
└── AuthhubError                # 网络层 / SDK 本身错误
    └── AuthhubHTTPError        # 后端返回 4xx/5xx
        └── AuthhubUnauthorized # 后端返回 401(特殊处理用)

行为约定

  • 不缓存任何 token → user_id 信息。AuthHub 是单点 SOT,权限变更秒级生效
  • OPTIONS 请求直接放行(CORS preflight 兼容)
  • bypass_paths 走前缀匹配;不走鉴权但仍注入空 ctx(FastAPI)
  • 超时默认 5 秒;线上建议结合熔断和重试策略由调用方控制
  • 调用 /sdk/authorize 时若 AuthHub 不可达 → SDK 抛 AuthhubError → 中间件返回 502; AuthHub 决策为 deny → 中间件返回 403。两种情况要分清楚

调试

需要看每次鉴权的细节?AuthHub /sdk/authorize 返回包含:

{
  "allow": false,
  "decision": "deny",
  "reason": "PhilVault 拒绝:用户 ... 在 cortexa 域对 rbac_cortexa::asset(read) 无授权",
  "user": {"id": "...", "username": "..."},
  "mapping": {"app_code": "cortexa", "method": "GET", "path": "/api/v1/asset/<id>", ...},
  "philvault_resource_id": "rbac_cortexa::asset",
  "action_code": "read"
}

在 Django view 里:print(request.authhub_outcome.raw) 看完整内容。

打开 AuthHub 「授权排查」页面(/diagnose),输入 user + method + path 可以 离线还原决策路径,不消耗 PhilVault 调用配额。

测试

cd authhub_sdk
pytest

22 个单测覆盖 client / Django 中间件 / FastAPI 依赖三个层,使用 httpx.MockTransport 模拟 AuthHub,零外部依赖。

版本

  • 0.1.1 — 修正包名为 authhub-rbac-sdk,更新 README
  • 0.1.0 — 初版。后续兼容性以 SemVer 为准。

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

authhub_rbac_sdk-0.1.2.tar.gz (19.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

authhub_rbac_sdk-0.1.2-py3-none-any.whl (19.8 kB view details)

Uploaded Python 3

File details

Details for the file authhub_rbac_sdk-0.1.2.tar.gz.

File metadata

  • Download URL: authhub_rbac_sdk-0.1.2.tar.gz
  • Upload date:
  • Size: 19.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.10.14

File hashes

Hashes for authhub_rbac_sdk-0.1.2.tar.gz
Algorithm Hash digest
SHA256 5e1fb6cbb65402678cfa7d54b8952faa866d10f38ceea8e762ef1e3bf6852efb
MD5 4990f9966f23bd17114e1845a11edb26
BLAKE2b-256 4f11d69b51288bc137876b61c05ce7fd0238ead5b5d224ae3610c591b42d896f

See more details on using hashes here.

File details

Details for the file authhub_rbac_sdk-0.1.2-py3-none-any.whl.

File metadata

File hashes

Hashes for authhub_rbac_sdk-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 0b23844217f6e8795cb6f49e15d39590d407bd326a43eb6a6135754f2d307510
MD5 5e08becf886fb881cdad4c7a0d11b1e1
BLAKE2b-256 9447910bd2f6efde621db8acb294e9d45ae3383d9da25de248a4d8f3d12b49c4

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page