89 lines
2.9 KiB
Python
89 lines
2.9 KiB
Python
"""认证 API"""
|
|
import base64
|
|
import json
|
|
from fastapi import APIRouter, Depends, HTTPException
|
|
from pydantic import BaseModel
|
|
from sqlalchemy.orm import Session
|
|
from app.core.database import get_db
|
|
from app.core.casdoor import casdoor_sdk
|
|
from app.core.security import create_access_token
|
|
from app.core.config import settings
|
|
from app.models.user import User
|
|
from app.schemas.auth import Token, UserInfo
|
|
from datetime import datetime
|
|
|
|
router = APIRouter(prefix="/api/auth", tags=["认证"])
|
|
|
|
|
|
def decode_jwt_payload(token: str) -> dict:
|
|
"""直接解码 JWT payload,不验签(Casdoor 已完成认证)"""
|
|
payload_b64 = token.split(".")[1]
|
|
rem = len(payload_b64) % 4
|
|
if rem:
|
|
payload_b64 += "=" * (4 - rem)
|
|
return json.loads(base64.urlsafe_b64decode(payload_b64))
|
|
|
|
|
|
@router.get("/login")
|
|
def login():
|
|
"""获取 Casdoor 登录 URL"""
|
|
return {"url": casdoor_sdk.get_auth_link(settings.CASDOOR_REDIRECT_URL)}
|
|
|
|
|
|
class CallbackRequest(BaseModel):
|
|
code: str
|
|
state: str
|
|
|
|
|
|
@router.post("/callback", response_model=Token)
|
|
def callback(body: CallbackRequest, db: Session = Depends(get_db)):
|
|
"""Casdoor 登录回调"""
|
|
try:
|
|
token_response = casdoor_sdk.get_oauth_token(code=body.code)
|
|
if isinstance(token_response, dict) and "error" in token_response:
|
|
raise HTTPException(status_code=400, detail=token_response.get("error_description", token_response["error"]))
|
|
|
|
access_token = token_response.get("access_token") if isinstance(token_response, dict) else token_response
|
|
if not access_token:
|
|
raise HTTPException(status_code=400, detail="Casdoor 未返回 access_token")
|
|
|
|
casdoor_user = decode_jwt_payload(access_token)
|
|
|
|
user = db.query(User).filter(User.casdoor_id == casdoor_user["sub"]).first()
|
|
if not user:
|
|
user = User(
|
|
casdoor_id=casdoor_user["sub"],
|
|
username=casdoor_user.get("name") or casdoor_user.get("preferred_username", ""),
|
|
email=casdoor_user.get("email"),
|
|
role="user"
|
|
)
|
|
db.add(user)
|
|
|
|
user.last_login = datetime.utcnow()
|
|
db.commit()
|
|
|
|
jwt_token = create_access_token({"sub": str(user.id), "username": user.username})
|
|
return {"access_token": jwt_token}
|
|
except HTTPException:
|
|
raise
|
|
except Exception as e:
|
|
raise HTTPException(status_code=500, detail=str(e))
|
|
|
|
|
|
@router.get("/profile", response_model=UserInfo)
|
|
def get_profile(token: str, db: Session = Depends(get_db)):
|
|
"""获取当前用户信息"""
|
|
from app.core.security import verify_token
|
|
|
|
payload = verify_token(token)
|
|
if not payload:
|
|
raise HTTPException(status_code=401, detail="无效的令牌")
|
|
|
|
user = db.query(User).filter(User.id == int(payload["sub"])).first()
|
|
if not user:
|
|
raise HTTPException(status_code=404, detail="用户不存在")
|
|
|
|
return user
|
|
|
|
|