848f804169
- FastAPI 后端 + Vue 3 前端 - Docker Compose 一键部署 - Casdoor OAuth 认证集成 - LogHive 集中式日志 - 设备批量 CSV 导入/导出 - WebSocket 实时状态推送 - 企业微信告警通知 - fping 高性能并发 Ping 检测 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
89 lines
2.8 KiB
Python
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,
|
|
}
|