918bbed0fc
- 修复 deps.py 中 get_vn_service 的引用错误 (vn_service.vn_service -> vn_service) - 移除登录页面上的明文密码提示 - 改进前端错误处理,避免数据加载失败导致登录显示错误
114 lines
2.9 KiB
Python
114 lines
2.9 KiB
Python
"""
|
|
认证路由
|
|
处理用户登录、登出、Token 验证
|
|
"""
|
|
from fastapi import APIRouter, Depends, HTTPException, status
|
|
from datetime import timedelta
|
|
|
|
from ..models import (
|
|
LoginRequest, TokenResponse, TokenVerifyRequest, TokenVerifyResponse
|
|
)
|
|
from ..deps import (
|
|
get_current_user, authenticate_user, create_access_token,
|
|
ACCESS_TOKEN_EXPIRE_MINUTES
|
|
)
|
|
import logging
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
@router.post("/login", response_model=TokenResponse)
|
|
async def login(login_request: LoginRequest):
|
|
"""
|
|
用户登录
|
|
|
|
- **username**: 用户名
|
|
- **password**: 密码
|
|
|
|
返回 JWT Token
|
|
"""
|
|
# 验证用户凭证
|
|
user = authenticate_user(login_request.username, login_request.password)
|
|
|
|
if not user:
|
|
logger.warning(f"Failed login attempt for user: {login_request.username}")
|
|
raise HTTPException(
|
|
status_code=status.HTTP_401_UNAUTHORIZED,
|
|
detail="Incorrect username or password",
|
|
headers={"WWW-Authenticate": "Bearer"},
|
|
)
|
|
|
|
# 创建 Token
|
|
access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
|
|
access_token = create_access_token(
|
|
data={"sub": user["username"], "is_active": user["is_active"]},
|
|
expires_delta=access_token_expires
|
|
)
|
|
|
|
logger.info(f"User logged in: {user['username']}")
|
|
|
|
return TokenResponse(
|
|
access_token=access_token,
|
|
token_type="bearer",
|
|
expires_in=ACCESS_TOKEN_EXPIRE_MINUTES * 60
|
|
)
|
|
|
|
|
|
@router.post("/verify", response_model=TokenVerifyResponse)
|
|
async def verify_token(
|
|
verify_request: TokenVerifyRequest
|
|
):
|
|
"""
|
|
验证 Token 有效性
|
|
|
|
- **token**: JWT Token
|
|
|
|
返回 Token 是否有效及用户信息
|
|
"""
|
|
from ..deps import verify_token as do_verify_token
|
|
|
|
try:
|
|
payload = do_verify_token(verify_request.token)
|
|
username = payload.get("sub")
|
|
|
|
return TokenVerifyResponse(
|
|
valid=True,
|
|
user_info={
|
|
"username": username,
|
|
"is_active": payload.get("is_active", True),
|
|
"exp": payload.get("exp")
|
|
}
|
|
)
|
|
except HTTPException:
|
|
return TokenVerifyResponse(valid=False, user_info=None)
|
|
|
|
|
|
@router.get("/me")
|
|
async def get_current_user_info(current_user: dict = Depends(get_current_user)):
|
|
"""
|
|
获取当前用户信息
|
|
|
|
需要有效的 JWT Token
|
|
"""
|
|
return {
|
|
"username": current_user["username"],
|
|
"is_active": current_user["is_active"],
|
|
"exp": current_user.get("exp")
|
|
}
|
|
|
|
|
|
@router.post("/logout")
|
|
async def logout(current_user: dict = Depends(get_current_user)):
|
|
"""
|
|
用户登出
|
|
|
|
注:JWT 是无状态的,客户端只需删除 Token 即可
|
|
此接口主要用于记录日志或执行清理操作
|
|
"""
|
|
username = current_user.get("username", "unknown")
|
|
logger.info(f"User logged out: {username}")
|
|
|
|
return {"message": "Successfully logged out"}
|