小程序后端接入微信登录与家长头像能力
This commit is contained in:
@@ -1,17 +1,23 @@
|
||||
import logging
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Request, status
|
||||
from pydantic import BaseModel
|
||||
from sqlalchemy import text
|
||||
from fastapi import APIRouter, Depends, HTTPException, Request
|
||||
from pydantic import BaseModel, Field
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
try:
|
||||
from app.db import get_db
|
||||
from app.security import create_access_token
|
||||
from app.service.parent import ParentService
|
||||
from app.service.wechat_login import (
|
||||
WechatAuthError,
|
||||
WechatAuthService,
|
||||
get_wechat_auth_service,
|
||||
)
|
||||
except ModuleNotFoundError:
|
||||
from db import get_db
|
||||
from security import create_access_token
|
||||
from service.parent import ParentService
|
||||
from service.wechat_login import WechatAuthError, WechatAuthService, get_wechat_auth_service
|
||||
|
||||
|
||||
router = APIRouter(prefix="/auth", tags=["auth"])
|
||||
@@ -19,15 +25,14 @@ logger = logging.getLogger("app.auth")
|
||||
|
||||
|
||||
class LoginRequest(BaseModel):
|
||||
username: Optional[str] = None
|
||||
password: Optional[str] = None
|
||||
code: Optional[str] = None
|
||||
nickname: Optional[str] = None
|
||||
avatar_url: Optional[str] = None
|
||||
code: str = Field(min_length=1, max_length=191)
|
||||
nickname: str | None = Field(default=None, max_length=64)
|
||||
avatar_url: str | None = Field(default=None, max_length=255)
|
||||
|
||||
|
||||
class LoginResponse(BaseModel):
|
||||
access_token: str
|
||||
token_type: str = "bearer"
|
||||
expires_in: int
|
||||
user_id: int
|
||||
|
||||
@@ -37,51 +42,38 @@ def login(
|
||||
payload: LoginRequest,
|
||||
request: Request,
|
||||
db: Session = Depends(get_db),
|
||||
wechat_auth_service: WechatAuthService = Depends(get_wechat_auth_service),
|
||||
) -> LoginResponse:
|
||||
logger.info(f"/auth/login called with code={payload.code[:20] if payload.code else None}...")
|
||||
identifier = payload.code or payload.username
|
||||
if not identifier:
|
||||
raise HTTPException(status_code=400, detail="username or code is required")
|
||||
del request
|
||||
logger.info("/auth/login called")
|
||||
|
||||
with db.begin():
|
||||
row = (
|
||||
db.execute(
|
||||
text("SELECT user_id FROM parents WHERE openid = :openid"),
|
||||
{"openid": identifier},
|
||||
).mappings().first()
|
||||
try:
|
||||
wechat_session = wechat_auth_service.exchange_code(payload.code)
|
||||
except WechatAuthError as exc:
|
||||
logger.warning(
|
||||
"wechat login failed",
|
||||
extra={
|
||||
"event": "wechat_login_failed",
|
||||
"status_code": exc.status_code,
|
||||
"errcode": exc.errcode,
|
||||
},
|
||||
)
|
||||
raise HTTPException(status_code=exc.status_code, detail=str(exc)) from exc
|
||||
|
||||
if row:
|
||||
user_id = int(row["user_id"])
|
||||
logger.info(f"Existing user found: user_id={user_id}")
|
||||
if payload.nickname or payload.avatar_url:
|
||||
db.execute(
|
||||
text(
|
||||
"""
|
||||
UPDATE parents
|
||||
SET nickname = COALESCE(:nickname, nickname),
|
||||
avatar_url = COALESCE(:avatar_url, avatar_url)
|
||||
WHERE user_id = :user_id
|
||||
"""
|
||||
),
|
||||
{"user_id": user_id, "nickname": payload.nickname, "avatar_url": payload.avatar_url},
|
||||
)
|
||||
else:
|
||||
logger.info("Creating new user...")
|
||||
db.execute(
|
||||
text(
|
||||
"INSERT INTO parents (openid, nickname, avatar_url, status) VALUES (:openid, :nickname, :avatar_url, 1)"
|
||||
),
|
||||
{"openid": identifier, "nickname": payload.nickname, "avatar_url": payload.avatar_url},
|
||||
)
|
||||
user_id = int(db.execute(text("SELECT last_insert_rowid()")).scalar_one())
|
||||
logger.info(f"New user created: user_id={user_id}")
|
||||
parent_service = ParentService(db)
|
||||
parent = parent_service.create(
|
||||
openid=wechat_session.openid,
|
||||
unionid=wechat_session.unionid,
|
||||
nickname=payload.nickname,
|
||||
avatar_url=payload.avatar_url,
|
||||
)
|
||||
user_id = int(parent["user_id"])
|
||||
|
||||
access_token, expires_in = create_access_token(user_id=user_id)
|
||||
logger.info(f"Login succeeded: user_id={user_id}, expires_in={expires_in}")
|
||||
logger.info("wechat login succeeded", extra={"event": "wechat_login_succeeded", "user_id": user_id})
|
||||
return LoginResponse(access_token=access_token, expires_in=expires_in, user_id=user_id)
|
||||
|
||||
|
||||
@router.post("/logout")
|
||||
def logout(request: Request):
|
||||
return {"message": "logged out"}
|
||||
return {"message": "logged out"}
|
||||
|
||||
Reference in New Issue
Block a user