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

改动内容:新增微信 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
+62
View File
@@ -68,6 +68,68 @@ def test_sms_login_and_me_flow(client) -> None:
assert r.json()["ok"] is True
def test_wechat_login_creates_and_reuses_user(client, monkeypatch) -> None:
def fake_code_to_userinfo(code: str) -> dict:
return {
"openid": "openid-login-create",
"unionid": "union-login-create",
"nickname": "微信昵称",
"avatar_url": "https://wx.example/avatar.png",
"raw": {"code": code},
}
monkeypatch.setattr("app.api.v1.auth.code_to_userinfo", fake_code_to_userinfo)
r = client.post("/api/v1/auth/wechat-login", json={"code": "code-a", "device_id": "dev-wx"})
assert r.status_code == 200, r.text
first = r.json()
assert first["user"]["register_channel"] == "wechat"
assert first["user"]["phone"].startswith("wx_")
assert first["user"]["nickname"] == "微信昵称"
r = client.post("/api/v1/auth/wechat-login", json={"code": "code-b", "device_id": "dev-wx"})
assert r.status_code == 200, r.text
second = r.json()
assert second["user"]["id"] == first["user"]["id"]
assert second["user"]["phone"] == first["user"]["phone"]
def test_wechat_login_uses_existing_bound_user(client, monkeypatch) -> None:
from app.db.session import SessionLocal
from app.repositories import user as user_repo
db = SessionLocal()
try:
user = user_repo.upsert_user_for_login(
db,
phone="13600136000",
register_channel="sms",
)
user.wechat_openid = "openid-login-bound"
user.wechat_nickname = "已绑定昵称"
db.commit()
user_id = user.id
finally:
db.close()
def fake_code_to_userinfo(code: str) -> dict:
return {
"openid": "openid-login-bound",
"unionid": "union-login-bound",
"nickname": "新微信昵称",
"avatar_url": None,
"raw": {"code": code},
}
monkeypatch.setattr("app.api.v1.auth.code_to_userinfo", fake_code_to_userinfo)
r = client.post("/api/v1/auth/wechat-login", json={"code": "code-bound", "device_id": "dev-wx"})
assert r.status_code == 200, r.text
body = r.json()
assert body["user"]["id"] == user_id
assert body["user"]["phone"] == "13600136000"
def test_sms_send_too_frequent(client) -> None:
phone = "13900139000"
assert client.post("/api/v1/auth/sms/send", json={"phone": phone}).status_code == 200
+1
View File
@@ -14,6 +14,7 @@ def test_openapi_loads(client) -> None:
paths = resp.json()["paths"]
# auth endpoints 都注册了
assert "/api/v1/auth/jverify-login" in paths
assert "/api/v1/auth/wechat-login" in paths
assert "/api/v1/auth/sms/send" in paths
assert "/api/v1/auth/sms/login" in paths
assert "/api/v1/auth/refresh" in paths