"""登录 / 退出 / 当前用户 / 用户自己的设置(昵称、密码)。""" from __future__ import annotations from fastapi import APIRouter, Depends, HTTPException, Request, Response from sqlalchemy.orm import Session from .. import config, security from ..db import get_db from ..models import User from ..schemas import LoginIn, PasswordIn, ProfileIn router = APIRouter() @router.post("/auth/login") def login(body: LoginIn, response: Response, db: Session = Depends(get_db)): user = db.query(User).filter(User.username == (body.username or "").strip()).one_or_none() if user is None or not security.verify_password(body.password or "", user.password_hash, user.password_salt): raise HTTPException(status_code=401, detail="用户名或密码不正确") if not user.active: raise HTTPException(status_code=403, detail="该账号已被停用,请联系管理员") token = security.start_session(db, user) response.set_cookie( security.SESSION_COOKIE, token, max_age=config.SESSION_DAYS * 86400, httponly=True, samesite="lax", path="/", ) return user.to_dict() @router.post("/auth/logout") def logout(request: Request, response: Response, db: Session = Depends(get_db)): token = request.cookies.get(security.SESSION_COOKIE) if token: db.query(security.UserSession).filter(security.UserSession.token == token).delete() db.commit() response.delete_cookie(security.SESSION_COOKIE, path="/") return {"ok": True} @router.get("/auth/me") def me(user: User = Depends(security.current_user)): return user.to_dict() @router.put("/auth/me") def update_me(body: ProfileIn, user: User = Depends(security.current_user), db: Session = Depends(get_db)): name = (body.name or "").strip() if not name: raise HTTPException(status_code=400, detail="昵称不能为空") user.name = name[:64] db.commit() return user.to_dict() @router.post("/auth/password") def change_password(body: PasswordIn, request: Request, response: Response, user: User = Depends(security.current_user), db: Session = Depends(get_db)): if not security.verify_password(body.old_password or "", user.password_hash, user.password_salt): raise HTTPException(status_code=400, detail="原密码不正确") new = (body.new_password or "").strip() if len(new) < 6: raise HTTPException(status_code=400, detail="新密码至少 6 位") user.password_hash, user.password_salt = security.hash_password(new) # 改密后其余设备全部下线,只保留当前这次登录 keep = request.cookies.get(security.SESSION_COOKIE) query = db.query(security.UserSession).filter(security.UserSession.user_id == user.id) if keep: query = query.filter(security.UserSession.token != keep) query.delete(synchronize_session=False) db.commit() return {"ok": True}