Skip to main content

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

Project description

authhub_sdk

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

核心约束:子平台只调 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/

安装

仓库内开发:

# 基础安装(只用 AuthhubClient / AsyncAuthhubClient)
pip install /path/to/authhub/authhub_sdk

# Django 接入(自动带上 Django >=4.2)
pip install "authhub-sdk[django] @ file:///path/to/authhub/authhub_sdk"

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

# Django + FastAPI 都装
pip install "authhub-sdk[all] @ 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 上游包不会发生命名冲突。

三件套环境变量

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

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")

显式传配置(不走 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/"],
}

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
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.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.0.tar.gz (17.8 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.0-py3-none-any.whl (18.3 kB view details)

Uploaded Python 3

File details

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

File metadata

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

File hashes

Hashes for authhub_rbac_sdk-0.1.0.tar.gz
Algorithm Hash digest
SHA256 66c0c4db0324b6d7288652494a1faefcc6ce17c664f47ab6d377f100b46b8184
MD5 8354f98806e288c6932a1d075d7405a9
BLAKE2b-256 6a572310c1f28b417a29426d1ab752754caf69a78bc33dec75665066638335ba

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for authhub_rbac_sdk-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 4d4dfb7635b6e80283dc47e7a9de9ddd952c0d1d3b06ab223630ced71e16a488
MD5 a6f9e2561506d671a35ee113e344947e
BLAKE2b-256 521fc61eb2d1f8a26ca48efda78794954d71391421c445c97527e75907c337c7

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