jiachenlong/backend/app/routers/auth.py

227 lines
7.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 认证路由 - 使用字段编码
from fastapi import APIRouter, Depends, HTTPException, status, Body
from fastapi.security import OAuth2PasswordRequestForm
from sqlalchemy.orm import Session
from app.core.database import get_db
from app.core.auth import verify_password, create_access_token, get_password_hash, get_current_user
from app.models.models import User
from app.schemas.schemas import Token, UserCreate, UserResponse
router = APIRouter(prefix="/api/auth", tags=["认证"])
def generate_user_code(db):
"""生成用户编码从201开始按自然数顺序递增"""
# 查找最大的user_code
max_code = db.query(User.user_code).filter(User.user_code != None).order_by(User.user_code.desc()).first()
if max_code and max_code[0]:
try:
num = int(max_code[0]) + 1
if num < 201:
num = 201
return str(num)
except:
pass
return "201"
@router.post("/register", response_model=UserResponse)
def register(user_data: UserCreate, db: Session = Depends(get_db)):
"""用户注册"""
# 检查用户名是否已存在
existing_user = db.query(User).filter(User.f01_01_name == user_data.f01_01_name).first()
if existing_user:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="f01_01_name: 用户名已存在"
)
# 检查邮箱是否已存在
# 检查手机号是否已存在
if user_data.phone:
existing_phone = db.query(User).filter(User.phone == user_data.phone).first()
if existing_phone:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="E00040:该手机号已被注册,请更换手机号"
)
if user_data.email:
existing_email = db.query(User).filter(User.email == user_data.email).first()
if existing_email:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="E00041:该邮箱已被注册,请更换邮箱"
)
# 处理邀请码
invited_by_user = None
if user_data.invite_code:
# 查找邀请人
invited_by_user = db.query(User).filter(User.user_code == user_data.invite_code).first()
if not invited_by_user:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="E00042:邀请码无效"
)
# 创建用户
import uuid
hashed_password = get_password_hash(user_data.password)
generated_code = generate_user_code(db)
user = User(
f99_90_id=str(uuid.uuid4()),
f99_91_user_id=str(uuid.uuid4()),
user_code=generated_code,
f01_01_name=user_data.f01_01_name,
email=user_data.email,
phone=user_data.phone,
avatar=user_data.avatar,
address=user_data.address,
bio=user_data.bio,
password=hashed_password,
role="user"
)
db.add(user)
db.flush() # 确保获取user ID
# 更新邀请人、被邀请人的关联关系
if invited_by_user:
# 记录是被谁邀请的
user.f01_13_invite_code = invited_by_user.user_code
# 增加邀请人的邀请计数
invited_by_user.f99_101_invited_count = (invited_by_user.f99_101_invited_count or 0) + 1
# 生成自己的邀请码用自己的user_code
user.f01_13_invite_code = generated_code
db.commit()
db.refresh(user)
return user
@router.post("/login", response_model=Token)
def login(
form_data: OAuth2PasswordRequestForm = Depends(),
db: Session = Depends(get_db)
):
"""用户登录 - 支持用户名或用户编码登录"""
# 先尝试用户名登录
user = db.query(User).filter(User.f01_01_name == form_data.username).first()
# 如果用户名不存在,尝试用户编码登录
if not user:
user = db.query(User).filter(User.user_code == form_data.username).first()
if not user:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="E00011: 用户名或密码错误",
headers={"WWW-Authenticate": "Bearer"},
)
# 验证密码
if not verify_password(form_data.password, user.password):
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="E00011: 用户名或密码错误",
headers={"WWW-Authenticate": "Bearer"},
)
# 更新登录次数和最后登录时间
from datetime import datetime
user.f99_98_login_count = (user.f99_98_login_count or 0) + 1
user.f99_99_last_login = datetime.now()
db.commit()
# 生成 token
access_token = create_access_token(data={"sub": user.f99_90_id})
return {
"access_token": access_token,
"token_type": "bearer"
}
@router.get("/me", response_model=UserResponse)
def get_current_user_info(
current_user: User = Depends(lambda: None)
):
"""获取当前用户信息"""
raise HTTPException(
status_code=status.HTTP_501_NOT_IMPLEMENTED,
detail="请使用正确的依赖注入"
)
@router.post("/change-password")
def change_password(
old_password: str = Body(...),
new_password: str = Body(...),
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db)
):
"""修改当前用户密码"""
from app.core.auth import verify_password, get_password_hash
# 在当前session中重新查询用户
user = db.query(User).filter(User.f99_90_id == current_user.f99_90_id).first()
if not user:
raise HTTPException(status_code=404, detail="用户不存在")
# 验证旧密码
if not verify_password(old_password, user.password):
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="当前密码错误"
)
# 更新密码
user.password = get_password_hash(new_password)
db.commit()
return {"message": "密码修改成功"}
# ============ 短信验证码接口 ============
@router.post("/send-verification-code")
def send_verification_code(
phone: str = Body(..., min_length=11, max_length=11),
purpose: str = Body("register") # register | login | reset_password
):
"""发送短信验证码"""
from app.services.sms import send_verification_code as send_sms
# 验证手机号格式
if not phone.startswith("1") or len(phone) != 11:
return {"success": False, "message": "手机号格式不正确"}
result = send_sms(phone)
if result["success"]:
return {
"success": True,
"message": f"验证码已发送到 {phone[:3]}****{phone[7:]}",
"expire": result.get("expire", 300)
}
else:
return result
@router.post("/verify-code")
def verify_code(
phone: str = Body(...),
code: str = Body(..., min_length=6, max_length=6)
):
"""验证短信验证码(仅验证,不执行后续操作)"""
from app.services.sms import verify_code as check_code
is_valid = check_code(phone, code)
if is_valid:
return {"success": True, "message": "验证成功"}
else:
return {"success": False, "message": "验证码错误或已过期"}