接入微信一键登录服务端接口

改动内容:新增微信 code 换 openid 集成、/api/v1/auth/wechat-login 登录接口、微信用户创建/复用逻辑和测试覆盖。

验证方式:python -m pytest tests\\test_auth.py tests\\test_health.py -q 通过。
This commit is contained in:
lowmaster-chen
2026-06-29 22:21:33 +08:00
parent b622f76a02
commit 1913dbcc6e
7 changed files with 243 additions and 2 deletions
+32
View File
@@ -2,6 +2,7 @@
路由前缀 `/api/v1/auth`,包含:
POST /jverify-login 极光一键登录(loginToken → 手机号 → 注册即登录 → 签 JWT)
POST /wechat-login 微信 App 授权登录(code → openid → 注册即登录 → 签 JWT)
POST /sms/send 发短信验证码(mock 阶段任意 6 位通过)
POST /sms/login 手机号 + 验证码登录
POST /refresh 用 refresh_token 换新的 token 对
@@ -20,6 +21,7 @@ from app.core.ratelimit import enforce_rate_limit, rate_limit
from app.core.security import TokenError, decode_token, issue_token_pair
from app.integrations.jiguang import JiguangError, mask_phone, verify_and_get_phone
from app.integrations.sms import SmsError, send_code, verify_code
from app.integrations.wechat_login import WechatLoginError, code_to_userinfo
from app.repositories import onboarding as onboarding_repo
from app.repositories import user as user_repo
from app.schemas.auth import (
@@ -32,6 +34,7 @@ from app.schemas.auth import (
TokenPair,
TokenWithUser,
UserOut,
WechatLoginRequest,
)
logger = logging.getLogger("shagua.auth")
@@ -84,6 +87,35 @@ def jverify_login(req: JverifyLoginRequest, db: DbSession) -> TokenWithUser:
return _login_response(user, onboarding_completed=completed)
# ===================== 微信 App 登录 =====================
@router.post(
"/wechat-login",
response_model=TokenWithUser,
summary="微信一键登录",
dependencies=[Depends(rate_limit(20, 60, "wechat-login"))],
)
def wechat_login(req: WechatLoginRequest, db: DbSession) -> TokenWithUser:
try:
info = code_to_userinfo(req.code)
except WechatLoginError as e:
logger.error("[WECHAT] login code exchange failed: %s", e, exc_info=True)
raise HTTPException(status_code=502, detail=str(e)) from e
user = user_repo.upsert_user_for_wechat_login(
db,
openid=info["openid"],
nickname=info.get("nickname"),
avatar_url=info.get("avatar_url"),
)
if user.status != "active":
raise HTTPException(status_code=403, detail="account disabled")
completed = onboarding_repo.is_completed(db, user_id=user.id, device_id=req.device_id)
logger.info("wechat_login ok user_id=%d onboarded=%s", user.id, completed)
return _login_response(user, onboarding_completed=completed)
# ===================== 短信登录 =====================
@router.post(