imetting_backend/app/api/endpoints/auth.py

118 lines
4.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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, role_id 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:
raise HTTPException(status_code=401, detail="用户名或密码错误")
# 创建JWT token
token_data = {
"user_id": user['user_id'],
"username": user['username'],
"caption": user['caption'],
"role_id": user['role_id']
}
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,
role_id=user['role_id']
)
@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'],
"role_id": current_user['role_id']
}
new_token = jwt_service.create_access_token(token_data)
return {"token": new_token}