modify: auth插件拆分,将token签发部分交给网关
This commit is contained in:
@@ -0,0 +1 @@
|
||||
from . import github # noqa: F401
|
||||
@@ -0,0 +1,74 @@
|
||||
"""GitHub OAuth 提供方对接(授权码模式)。
|
||||
|
||||
HTTP 调用独立成模块函数,便于测试替身(monkeypatch)注入。
|
||||
"""
|
||||
import logging
|
||||
|
||||
import httpx
|
||||
|
||||
logger = logging.getLogger("plugins.auth_oauth.github")
|
||||
|
||||
_TOKEN_URL = "https://github.com/login/oauth/access_token"
|
||||
_USER_API = "https://api.github.com/user"
|
||||
_USER_EMAILS_API = "https://api.github.com/user/emails"
|
||||
|
||||
|
||||
async def exchange_code(client_id: str, client_secret: str, code: str,
|
||||
redirect_uri: str) -> str:
|
||||
"""授权码换 access_token,失败抛 RuntimeError(业务语义,调用方转 fail 响应)。"""
|
||||
async with httpx.AsyncClient(timeout=10.0) as client:
|
||||
resp = await client.post(
|
||||
_TOKEN_URL,
|
||||
json={
|
||||
"client_id": client_id,
|
||||
"client_secret": client_secret,
|
||||
"code": code,
|
||||
"redirect_uri": redirect_uri,
|
||||
},
|
||||
headers={"Accept": "application/json"},
|
||||
)
|
||||
data = resp.json()
|
||||
if "access_token" not in data:
|
||||
detail = data.get("error_description") or data.get("error") or data
|
||||
raise RuntimeError(f"GitHub 授权码换取失败: {detail}")
|
||||
return data["access_token"]
|
||||
|
||||
|
||||
async def fetch_user(access_token: str) -> dict:
|
||||
"""拉取 GitHub 用户并归一化为建号 profile。
|
||||
|
||||
Returns:
|
||||
{uid, username, email, full_name, avatar_url}
|
||||
Raises:
|
||||
RuntimeError: API 失败或拿不到邮箱(users.email 非空唯一,必须可得)。
|
||||
"""
|
||||
async with httpx.AsyncClient(timeout=10.0) as client:
|
||||
headers = {
|
||||
"Authorization": f"Bearer {access_token}",
|
||||
"Accept": "application/vnd.github+json",
|
||||
}
|
||||
resp = await client.get(_USER_API, headers=headers)
|
||||
if resp.status_code != 200:
|
||||
raise RuntimeError(f"GitHub 用户信息获取失败: HTTP {resp.status_code}")
|
||||
u = resp.json()
|
||||
|
||||
email = u.get("email")
|
||||
if not email:
|
||||
# 私密邮箱:走 /user/emails 取主邮箱
|
||||
er = await client.get(_USER_EMAILS_API, headers=headers)
|
||||
if er.status_code == 200 and isinstance(er.json(), list):
|
||||
emails = er.json()
|
||||
primary = next(
|
||||
(e for e in emails if e.get("primary")), emails[0] if emails else None
|
||||
)
|
||||
email = primary.get("email") if primary else None
|
||||
if not email:
|
||||
raise RuntimeError("GitHub 账号未提供可用邮箱,无法创建账号")
|
||||
|
||||
return {
|
||||
"uid": str(u["id"]),
|
||||
"username": u.get("login") or f"github_{u['id']}",
|
||||
"email": email,
|
||||
"full_name": u.get("name"),
|
||||
"avatar_url": u.get("avatar_url"),
|
||||
}
|
||||
Reference in New Issue
Block a user