| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121 |
- """小程序鉴权:微信手机号快捷登录。"""
- from __future__ import annotations
- from datetime import datetime
- from fastapi import APIRouter, Depends
- from sqlalchemy.orm import Session
- from app.core.database import get_db
- from app.core.response import error_response, success_response
- from app.services import wx_qr_session
- from app.services.web_login_tokens import issue_web_login_tokens
- from app.services.wechat_login_service import resolve_wechat_login_user
- from app.services.wechat_mini_auth import (
- WechatMiniAuthError,
- code2session,
- get_phone_number,
- )
- router = APIRouter(prefix="/mini/auth", tags=["小程序鉴权"])
- @router.post("/wechat-login", response_model=dict)
- def wechat_login(body: dict, db: Session = Depends(get_db)):
- """手机号快捷登录:须 loginCode + phoneCode;匹配 phone_no 并绑定 wx_openid。"""
- login_code = (body.get("loginCode") or "").strip()
- phone_code = (body.get("phoneCode") or "").strip()
- if not phone_code:
- return error_response(400, "请授权手机号登录,或使用账号密码登录")
- try:
- sess = code2session(login_code)
- except WechatMiniAuthError as exc:
- return error_response(400, str(exc))
- try:
- phone = get_phone_number(phone_code)
- except WechatMiniAuthError as exc:
- return error_response(400, str(exc))
- user, err_msg, err_code = resolve_wechat_login_user(
- db, openid=sess["openid"], phone=phone
- )
- if err_msg:
- return error_response(err_code or 400, err_msg)
- unionid = (sess.get("unionid") or "").strip()
- if unionid and not (getattr(user, "wx_unionid", None) or "").strip():
- user.wx_unionid = unionid
- user.update_time = datetime.now()
- db.add(user)
- db.commit()
- db.refresh(user)
- try:
- data = issue_web_login_tokens(db, user)
- except ValueError as exc:
- return error_response(403, str(exc))
- return success_response(data)
- @router.post("/web-qr-scanned", response_model=dict)
- def web_qr_scanned(body: dict):
- raw = (body.get("sessionId") or body.get("scene") or "").strip()
- sid = wx_qr_session.resolve_session_id(raw) or raw
- data = wx_qr_session.get_session(sid)
- if not data or data.get("status") in ("expired", "consumed"):
- return error_response(400, "二维码已过期,请在电脑上刷新后重扫")
- wx_qr_session.mark_scanned(sid)
- return success_response({"ok": True})
- @router.post("/web-qr-confirm", response_model=dict)
- def web_qr_confirm(body: dict, db: Session = Depends(get_db)):
- raw = (body.get("sessionId") or body.get("scene") or "").strip()
- sid = wx_qr_session.resolve_session_id(raw) or raw
- data = wx_qr_session.get_session(sid)
- if not data or data.get("status") in ("expired", "consumed", "failed"):
- return error_response(400, "二维码已过期,请在电脑上刷新后重扫")
- if data.get("status") == "success":
- return success_response({"ok": True, "message": "电脑端即将登录"})
- wx_qr_session.mark_scanned(sid)
- login_code = (body.get("loginCode") or "").strip()
- phone_code = (body.get("phoneCode") or "").strip()
- if not login_code or not phone_code:
- wx_qr_session.mark_failed(sid, "需要授权手机号才能完成扫码登录")
- return error_response(400, "需要授权手机号才能完成扫码登录")
- try:
- sess = code2session(login_code)
- phone = get_phone_number(phone_code)
- except WechatMiniAuthError as exc:
- wx_qr_session.mark_failed(sid, str(exc))
- return error_response(400, str(exc))
- user, err_msg, err_code = resolve_wechat_login_user(
- db, openid=sess["openid"], phone=phone
- )
- if err_msg:
- wx_qr_session.mark_failed(sid, err_msg)
- return error_response(err_code or 400, err_msg)
- unionid = (sess.get("unionid") or "").strip()
- if unionid and not (getattr(user, "wx_unionid", None) or "").strip():
- user.wx_unionid = unionid
- user.update_time = datetime.now()
- db.add(user)
- db.commit()
- db.refresh(user)
- try:
- tokens = issue_web_login_tokens(db, user)
- except ValueError as exc:
- wx_qr_session.mark_failed(sid, str(exc))
- return error_response(403, str(exc))
- if not wx_qr_session.mark_success(sid, tokens):
- return error_response(400, "二维码已过期,请在电脑上刷新后重扫")
- return success_response({"ok": True, "message": "电脑端即将登录,可关闭本页"})
|