PingWatch 网络设备离线监控系统
- FastAPI 后端 + Vue 3 前端 - Docker Compose 一键部署 - Casdoor OAuth 认证集成 - LogHive 集中式日志 - 设备批量 CSV 导入/导出 - WebSocket 实时状态推送 - 企业微信告警通知 - fping 高性能并发 Ping 检测 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
"""Casdoor 认证 API"""
|
||||
from datetime import datetime
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from pydantic import BaseModel
|
||||
|
||||
from app.core.deps import get_db
|
||||
from app.core.auth import create_access_token, exchange_code_for_user, get_current_user
|
||||
from app.models.user import User, UserRoleEnum
|
||||
|
||||
router = APIRouter(prefix="/api/auth", tags=["认证"])
|
||||
|
||||
|
||||
class LoginRequest(BaseModel):
|
||||
code: str # Casdoor 返回的 OAuth code
|
||||
|
||||
|
||||
class LoginResponse(BaseModel):
|
||||
token: str
|
||||
user: dict
|
||||
|
||||
|
||||
@router.post("/login", response_model=LoginResponse)
|
||||
async def login(data: LoginRequest, db: AsyncSession = Depends(get_db)):
|
||||
"""用 Casdoor OAuth code 登录"""
|
||||
casdoor_user = await exchange_code_for_user(data.code)
|
||||
if not casdoor_user:
|
||||
raise HTTPException(status_code=401, detail="Casdoor 认证失败")
|
||||
|
||||
# 从 id_token 中提取用户信息
|
||||
# id_token payload 一般包含: sub, name, preferred_username, email, displayName 等
|
||||
casdoor_uid = casdoor_user.get("sub") or casdoor_user.get("name", "")
|
||||
username = casdoor_user.get("preferred_username") or casdoor_user.get("name", casdoor_uid)
|
||||
display_name = casdoor_user.get("displayName", "")
|
||||
|
||||
if not casdoor_uid:
|
||||
# 尝试用 name 作为备用标识
|
||||
casdoor_uid = casdoor_user.get("name", "")
|
||||
if not casdoor_uid:
|
||||
raise HTTPException(status_code=401, detail="无法从 Casdoor 获取用户标识")
|
||||
|
||||
# 查找或创建本地用户
|
||||
result = await db.execute(select(User).where(User.casdoor_uid == casdoor_uid))
|
||||
user = result.scalar_one_or_none()
|
||||
|
||||
if not user:
|
||||
# 首次登录,自动创建 viewer 账号
|
||||
user = User(
|
||||
casdoor_uid=casdoor_uid,
|
||||
username=username,
|
||||
display_name=display_name or username,
|
||||
role=UserRoleEnum.viewer,
|
||||
)
|
||||
db.add(user)
|
||||
await db.commit()
|
||||
await db.refresh(user)
|
||||
logger.info(f"新用户自动创建: {username} (uid: {casdoor_uid})")
|
||||
|
||||
# 更新最后登录时间
|
||||
user.last_login_at = datetime.now()
|
||||
await db.commit()
|
||||
|
||||
# 签发 PingWatch JWT
|
||||
token = create_access_token(
|
||||
data={"sub": user.casdoor_uid, "role": user.role.value}
|
||||
)
|
||||
|
||||
return LoginResponse(
|
||||
token=token,
|
||||
user={
|
||||
"id": user.id,
|
||||
"username": user.username,
|
||||
"display_name": user.display_name,
|
||||
"role": user.role.value,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@router.get("/me")
|
||||
async def get_me(current_user: User = Depends(get_current_user)):
|
||||
"""获取当前登录用户信息"""
|
||||
return {
|
||||
"id": current_user.id,
|
||||
"username": current_user.username,
|
||||
"display_name": current_user.display_name,
|
||||
"role": current_user.role.value,
|
||||
}
|
||||
Reference in New Issue
Block a user