feat(auth-proxy): 补齐短信/扫码登录转发端点(send-code/phone-login/wx-qr/mp-qr等11个) + status透传login_modes + forward支持params

This commit is contained in:
Pine
2026-08-28 17:40:55 +08:00
parent 219136797f
commit a88cfebf8a
2 changed files with 144 additions and 0 deletions
+142
View File
@@ -62,6 +62,10 @@ class RegisterRequest(BaseModel):
class AuthStatusResponse(BaseModel):
enabled: bool
has_users: bool
# 登录方式(password/phone/wechat/miniprogram),供登录页渲染 Tab
login_modes: list[str] = ["password", "phone"]
wechat_login: bool = False
wx_qr: bool = False
class UpdateProfileRequest(BaseModel):
@@ -187,9 +191,147 @@ async def auth_status():
return AuthStatusResponse(
enabled=bool(data.get("enabled", True)),
has_users=bool(data.get("has_users", True)),
login_modes=data.get("login_modes") or ["password", "phone"],
wechat_login=bool(data.get("wechat_login", False)),
wx_qr=bool(data.get("wx_qr", False)),
)
# ── 短信验证码登录 ────────────────────────────────────────────────────────
class SendCodeRequest(BaseModel):
phone: str
class PhoneLoginRequest(BaseModel):
phone: str
code: str
@router.post("/send-code")
async def send_code(req: SendCodeRequest):
"""发送短信验证码:转发到服务端(未接入短信网关时返回演示码 stub_code)。"""
return await forward("POST", "/auth/send-code", body={"phone": req.phone})
@router.post("/phone-login")
async def phone_login(req: PhoneLoginRequest):
"""手机号验证码登录(未注册自动建号):转发到服务端,签发平台令牌。"""
data = await forward(
"POST", "/auth/phone-login",
body={"phone": req.phone, "code": req.code},
)
save_auth_token(data.get("token", ""))
return data
# ── 微信登录 / 绑定 ──────────────────────────────────────────────────────
class WxLoginRequest(BaseModel):
code: str
nickName: str = ""
avatarUrl: str = ""
class BindPhoneRequest(BaseModel):
phone: str
code: str
class WxPhoneRequest(BaseModel):
code: str
class UnbindRequest(BaseModel):
type: str
@router.post("/wx-login")
async def wx_login(req: WxLoginRequest):
"""小程序 wx.login code2session 登录:转发到服务端。"""
data = await forward("POST", "/auth/wx-login", body=req.model_dump())
save_auth_token(data.get("token", ""))
return data
@router.post("/wx-phone")
async def wx_phone(req: WxPhoneRequest, request: Request):
"""微信手机号快捷绑定(getPhoneNumber code):转发到服务端。"""
return await forward(
"POST", "/auth/wx-phone", body=req.model_dump(),
auth_header=request.headers.get("Authorization", ""),
)
@router.post("/bind-phone")
async def bind_phone(req: BindPhoneRequest, request: Request):
"""当前账号绑定手机号:转发到服务端,返回新令牌。"""
data = await forward(
"POST", "/auth/bind-phone", body=req.model_dump(),
auth_header=request.headers.get("Authorization", ""),
)
save_auth_token(data.get("token", ""))
return data
@router.post("/unbind")
async def unbind(req: UnbindRequest, request: Request):
"""解绑登录方式(保留至少一种):转发到服务端。"""
return await forward(
"POST", "/auth/unbind", body=req.model_dump(),
auth_header=request.headers.get("Authorization", ""),
)
# ── 扫码登录(微信开放平台 / 小程序):代理只转发 start/poll ─────────────
@router.get("/wx-qr/start")
async def wx_qr_start():
"""发起微信开放平台扫码登录:转发到服务端。"""
return await forward("GET", "/auth/wx-qr/start")
@router.get("/wx-qr/poll")
async def wx_qr_poll(scene: str):
"""轮询微信扫码登录状态:转发到服务端。"""
data = await forward("GET", "/auth/wx-qr/poll", params={"scene": scene})
if data.get("status") == "done" and data.get("token"):
save_auth_token(data["token"])
return data
@router.get("/mp-qr/start")
async def mp_qr_start():
"""发起小程序扫码登录(返回小程序码/二维码):转发到服务端。"""
return await forward("GET", "/auth/mp-qr/start")
@router.get("/mp-qr/poll")
async def mp_qr_poll(scene: str):
"""轮询小程序扫码登录状态:转发到服务端。"""
data = await forward("GET", "/auth/mp-qr/poll", params={"scene": scene})
if data.get("status") == "done" and data.get("token"):
save_auth_token(data["token"])
return data
@router.get("/mp-qr/bind-start")
async def mp_qr_bind_start(request: Request):
"""发起「绑定小程序」:转发到服务端(需登录)。"""
return await forward(
"GET", "/auth/mp-qr/bind-start",
auth_header=request.headers.get("Authorization", ""),
)
class MpQrConfirmRequest(BaseModel):
scene: str
code: str
@router.post("/mp-qr/confirm")
async def mp_qr_confirm(req: MpQrConfirmRequest):
"""小程序内确认扫码登录/绑定:转发到服务端。"""
return await forward("POST", "/auth/mp-qr/confirm", body=req.model_dump())
@router.get("/verify")
async def verify(request: Request):
"""校验调用方 Bearer token:转发到演示 FastAPI。"""
+2
View File
@@ -19,6 +19,7 @@ async def forward(
path: str,
*,
body: dict | None = None,
params: dict | None = None,
auth_header: str | None = None,
) -> Any:
"""把请求转发到 PineAgentsServer,返回其 JSON 响应体。
@@ -38,6 +39,7 @@ async def forward(
method,
path,
json=body,
params=params,
headers=headers,
)
except httpx.HTTPError as exc: