添加后端API和前端项目的初始目录结构,包括应用层模块、工具模块和模型定义 配置前后端的.dockerignore文件以排除开发环境文件 添加前端样式文件,包括字体、Tailwind CSS和主题配置 初始化Python虚拟环境中的类型标记文件
88 lines
2.5 KiB
Python
88 lines
2.5 KiB
Python
import uuid
|
|
|
|
from fastapi import APIRouter, HTTPException
|
|
from pymongo.errors import DuplicateKeyError
|
|
|
|
from app.models.user import User
|
|
from app.schemas.auth import WechatLoginRequest, PhoneLoginRequest, TokenResponse
|
|
from app.middleware.auth import create_access_token
|
|
from app.services.wechat import code_to_session
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
@router.post("/demo-login", response_model=TokenResponse)
|
|
async def demo_login():
|
|
"""Web 体验用的演示登录,每次创建独立的临时用户"""
|
|
demo_openid = f"demo_{uuid.uuid4().hex[:12]}"
|
|
user = User(
|
|
openid=demo_openid,
|
|
name="体验用户",
|
|
)
|
|
await user.insert()
|
|
|
|
token = create_access_token(str(user.id))
|
|
return TokenResponse(
|
|
access_token=token,
|
|
user_id=str(user.id),
|
|
is_new_user=True,
|
|
)
|
|
|
|
|
|
@router.post("/wechat-login", response_model=TokenResponse)
|
|
async def wechat_login(req: WechatLoginRequest):
|
|
"""微信小程序登录"""
|
|
try:
|
|
wechat_data = await code_to_session(req.code)
|
|
except Exception as e:
|
|
raise HTTPException(status_code=400, detail=str(e))
|
|
|
|
openid = wechat_data["openid"]
|
|
user = await User.find_one(User.openid == openid)
|
|
is_new = user is None
|
|
|
|
if not user:
|
|
user = User(
|
|
openid=openid,
|
|
session_key=wechat_data.get("session_key"),
|
|
union_id=wechat_data.get("unionid"),
|
|
)
|
|
await user.insert()
|
|
else:
|
|
user.session_key = wechat_data.get("session_key")
|
|
await user.save()
|
|
|
|
token = create_access_token(str(user.id))
|
|
return TokenResponse(
|
|
access_token=token,
|
|
user_id=str(user.id),
|
|
is_new_user=is_new,
|
|
)
|
|
|
|
|
|
@router.post("/phone-login", response_model=TokenResponse)
|
|
async def phone_login(req: PhoneLoginRequest):
|
|
"""手机号登录(简化版,生产环境需接入短信验证)"""
|
|
# TODO: 接入真实短信验证服务
|
|
if req.sms_code != "123456":
|
|
raise HTTPException(status_code=400, detail="验证码错误")
|
|
|
|
user = await User.find_one(User.phone == req.phone)
|
|
is_new = user is None
|
|
|
|
if not user:
|
|
try:
|
|
user = User(openid=f"phone_{req.phone}", phone=req.phone)
|
|
await user.insert()
|
|
except DuplicateKeyError:
|
|
# 并发竞态:另一个请求已创建该用户,回退查找
|
|
user = await User.find_one(User.phone == req.phone)
|
|
is_new = False
|
|
|
|
token = create_access_token(str(user.id))
|
|
return TokenResponse(
|
|
access_token=token,
|
|
user_id=str(user.id),
|
|
is_new_user=is_new,
|
|
)
|