Files
v6ole 848f804169 PingWatch 网络设备离线监控系统
- FastAPI 后端 + Vue 3 前端
- Docker Compose 一键部署
- Casdoor OAuth 认证集成
- LogHive 集中式日志
- 设备批量 CSV 导入/导出
- WebSocket 实时状态推送
- 企业微信告警通知
- fping 高性能并发 Ping 检测

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-09 15:02:04 +08:00

89 lines
2.8 KiB
Python

"""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,
}