from fastapi import APIRouter, HTTPException, Depends from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials from app.models.models import LoginRequest, LoginResponse from app.core.database import get_db_connection from app.services.jwt_service import jwt_service from app.core.auth import get_current_user import hashlib security = HTTPBearer() router = APIRouter() def hash_password(password: str) -> str: return hashlib.sha256(password.encode()).hexdigest() @router.post("/auth/login", response_model=LoginResponse) def login(request: LoginRequest): with get_db_connection() as connection: cursor = connection.cursor(dictionary=True) query = "SELECT user_id, username, caption, email, password_hash FROM users WHERE username = %s" cursor.execute(query, (request.username,)) user = cursor.fetchone() if not user: raise HTTPException(status_code=401, detail="用户名或密码错误") hashed_input = hash_password(request.password) if user['password_hash'] != hashed_input and user['password_hash'] != request.password: raise HTTPException(status_code=401, detail="用户名或密码错误") # 创建JWT token token_data = { "user_id": user['user_id'], "username": user['username'], "caption": user['caption'] } token = jwt_service.create_access_token(token_data) return LoginResponse( user_id=user['user_id'], username=user['username'], caption=user['caption'], email=user['email'], token=token ) @router.post("/auth/logout") def logout(credentials: HTTPAuthorizationCredentials = Depends(security)): """登出接口,撤销当前token""" token = credentials.credentials # 验证token并获取用户信息(不查询数据库) payload = jwt_service.verify_token(token) if not payload: raise HTTPException(status_code=401, detail="Invalid or expired token") user_id = payload.get("user_id") if not user_id: raise HTTPException(status_code=401, detail="Invalid token payload") # 撤销当前token revoked = jwt_service.revoke_token(token, user_id) if revoked: return {"message": "Logged out successfully"} else: return {"message": "Already logged out or token not found"} @router.post("/auth/logout-all") def logout_all(current_user: dict = Depends(get_current_user)): """登出所有设备""" user_id = current_user['user_id'] revoked_count = jwt_service.revoke_all_user_tokens(user_id) return {"message": f"Logged out from {revoked_count} devices"} @router.post("/auth/admin/revoke-user-tokens/{user_id}") def admin_revoke_user_tokens(user_id: int, credentials: HTTPAuthorizationCredentials = Depends(security)): """管理员功能:撤销指定用户的所有token""" token = credentials.credentials # 验证管理员token(不查询数据库) payload = jwt_service.verify_token(token) if not payload: raise HTTPException(status_code=401, detail="Invalid or expired token") admin_user_id = payload.get("user_id") if not admin_user_id: raise HTTPException(status_code=401, detail="Invalid token payload") # 这里可以添加管理员权限检查,目前暂时允许任何登录用户操作 # if not payload.get('is_admin'): # raise HTTPException(status_code=403, detail="需要管理员权限") revoked_count = jwt_service.revoke_all_user_tokens(user_id) return {"message": f"Revoked {revoked_count} tokens for user {user_id}"} @router.get("/auth/me") def get_me(current_user: dict = Depends(get_current_user)): """获取当前用户信息""" return current_user @router.post("/auth/refresh") def refresh_token(current_user: dict = Depends(get_current_user)): """刷新token""" # 这里需要从请求中获取当前token,为简化先返回新token token_data = { "user_id": current_user['user_id'], "username": current_user['username'], "caption": current_user['caption'] } new_token = jwt_service.create_access_token(token_data) return {"token": new_token}