"""认证路由""" from fastapi import APIRouter, Depends, HTTPException, status from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials from pydantic import BaseModel from typing import Optional from sqlalchemy.orm import Session from ..database import get_db from ..services.auth import ( authenticate_user, create_access_token, decode_token, update_last_login, hash_password, TokenData, UserInfo ) from ..models.user import User router = APIRouter(prefix="/auth", tags=["认证"]) security = HTTPBearer() class LoginRequest(BaseModel): """登录请求""" username: str password: str class LoginResponse(BaseModel): """登录响应""" success: bool token: Optional[str] = None user: Optional[UserInfo] = None error: Optional[str] = None class ChangePasswordRequest(BaseModel): """修改密码请求""" old_password: str new_password: str # 权限依赖 async def get_current_user( credentials: HTTPAuthorizationCredentials = Depends(security), db: Session = Depends(get_db) ) -> User: """获取当前用户""" token = credentials.credentials token_data = decode_token(token) if not token_data: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Token 无效或已过期" ) user = db.query(User).filter(User.id == token_data.user_id).first() if not user or user.status != 1: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="用户不存在或已禁用" ) return user async def require_admin(user: User = Depends(get_current_user)) -> User: """要求管理员权限""" if user.role != 'admin': raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="需要管理员权限" ) return user async def require_operator(user: User = Depends(get_current_user)) -> User: """要求操作员以上权限""" if user.role not in ('admin', 'operator'): raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="需要操作员以上权限" ) return user # API 端点 @router.post("/login", response_model=LoginResponse) async def login(request: LoginRequest, db: Session = Depends(get_db)): """用户登录""" user = authenticate_user(db, request.username, request.password) if not user: return LoginResponse(success=False, error="用户名或密码错误") # 更新登录时间 update_last_login(db, user.id) # 生成 Token token = create_access_token({ "user_id": user.id, "username": user.username, "role": user.role }) return LoginResponse( success=True, token=token, user=UserInfo( id=user.id, username=user.username, nickname=user.nickname, role=user.role ) ) @router.get("/me", response_model=UserInfo) async def get_me(user: User = Depends(get_current_user)): """获取当前用户信息""" return UserInfo( id=user.id, username=user.username, nickname=user.nickname, role=user.role ) @router.post("/change-password") async def change_password( request: ChangePasswordRequest, user: User = Depends(get_current_user), db: Session = Depends(get_db) ): """修改密码""" from ..services.auth import verify_password if not verify_password(request.old_password, user.password_hash): raise HTTPException(status_code=400, detail="原密码错误") new_hash = hash_password(request.new_password) db.query(User).filter(User.id == user.id).update({"password_hash": new_hash}) db.commit() return {"success": True, "message": "密码修改成功"} @router.get("/users") async def list_users( user: User = Depends(require_admin), db: Session = Depends(get_db) ): """获取用户列表(仅管理员)""" users = db.query(User).all() return [ { "id": u.id, "username": u.username, "nickname": u.nickname, "role": u.role, "status": u.status, "last_login_at": u.last_login_at, "created_at": u.created_at } for u in users ] class CreateUserRequest(BaseModel): username: str password: str nickname: Optional[str] = None role: str = "viewer" @router.post("/users") async def create_user( request: CreateUserRequest, user: User = Depends(require_admin), db: Session = Depends(get_db) ): """创建用户(仅管理员)""" # 检查用户名是否存在 exists = db.query(User).filter(User.username == request.username).first() if exists: raise HTTPException(status_code=400, detail="用户名已存在") new_user = User( username=request.username, password_hash=hash_password(request.password), nickname=request.nickname, role=request.role, status=1 ) db.add(new_user) db.commit() db.refresh(new_user) return {"success": True, "id": new_user.id} @router.delete("/users/{user_id}") async def delete_user( user_id: int, user: User = Depends(require_admin), db: Session = Depends(get_db) ): """删除用户(仅管理员)""" if user_id == user.id: raise HTTPException(status_code=400, detail="不能删除自己") target = db.query(User).filter(User.id == user_id).first() if not target: raise HTTPException(status_code=404, detail="用户不存在") db.delete(target) db.commit() return {"success": True}