Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions .env.template
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,57 @@ TAVILY_API_KEY= # 获取搜索服务的 api key 请访问 https://app.tavily.co
# THREAD_PVC=yuxi-thread
# SKILLS_PVC=yuxi-skills # 当前代码会读取,但 Pod 挂载实际仍只使用 THREAD_PVC

# =============================================================================
# OIDC 认证配置
# =============================================================================
# 是否启用 OIDC 认证 (true/false)
# OIDC_ENABLED=false

# 认证源名称(显示在登录按钮上的文字,建议简短且具有辨识度, 默认: OIDC登录)
# OIDC_PROVIDER_NAME="OIDC登录"

# OIDC Provider 的 Issuer URL (例如: https://auth.example.com)
# OIDC_ISSUER_URL=

# OIDC Client ID
# OIDC_CLIENT_ID=

# OIDC Client Secret
# OIDC_CLIENT_SECRET=

# OIDC 回调 URL (可选,默认自动构建为 /api/auth/oidc/callback, 不建议自定义)
# 需要确保此 URL 在 OIDC Provider 中已注册
# OIDC_REDIRECT_URI=

# 授权端点 (可选,自动从 discovery 获取)
# OIDC_AUTHORIZATION_ENDPOINT=

# Token 端点 (可选,自动从 discovery 获取)
# OIDC_TOKEN_ENDPOINT=

# UserInfo 端点 (可选,自动从 discovery 获取)
# OIDC_USERINFO_ENDPOINT=

# 登出端点 (可选,自动从 discovery 获取)
# OIDC_END_SESSION_ENDPOINT=

# 请求的 scope (默认: openid profile email)
# OIDC_SCOPES=openid profile email

# 是否自动创建用户 (true/false,默认: true)
# OIDC_AUTO_CREATE_USER=true

# OIDC 用户的默认角色 (user/admin,默认: user)
# OIDC_DEFAULT_ROLE=user

# OIDC 用户的默认部门名称 (默认: OIDC用户)
# OIDC_DEFAULT_DEPARTMENT=OIDC用户

# 用户名映射字段 (默认: preferred_username)
# OIDC_USERNAME_CLAIM=preferred_username

# 邮箱映射字段 (默认: email)
# OIDC_EMAIL_CLAIM=email

# 姓名映射字段 (默认: name)
# OIDC_NAME_CLAIM=name
50 changes: 47 additions & 3 deletions backend/server/routers/auth_router.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@
import uuid
from yuxi.utils import logger

from fastapi import APIRouter, Depends, HTTPException, Request, status, UploadFile, File
from fastapi import APIRouter, Body, Depends, HTTPException, Request, status, UploadFile, File
from fastapi.security import OAuth2PasswordRequestForm
from fastapi.responses import RedirectResponse
from pydantic import BaseModel
from sqlalchemy import func, select
from sqlalchemy.ext.asyncio import AsyncSession
Expand All @@ -25,6 +26,16 @@
from yuxi.storage.minio import aupload_file_to_minio
from yuxi.utils.datetime_utils import utc_now_naive

# OIDC 认证相关导入
from server.routers.auth_router_oidc import (
get_oidc_config_handler,
oidc_callback_handler,
oidc_exchange_code_handler,
oidc_login_url_handler,
OIDCConfigResponse,
OIDCLoginResponse,
)

# 创建路由器
auth = APIRouter(prefix="/auth", tags=["authentication"])

Expand Down Expand Up @@ -672,8 +683,8 @@ async def delete_user(
# 软删除:标记删除状态并脱敏
import hashlib

# 生成4位哈希(基于user_id保证唯一性
hash_suffix = hashlib.sha256(user.user_id.encode()).hexdigest()[:4]
# 生成4位哈希(基于 user_id + id,避免历史软删除记录重名冲突
hash_suffix = hashlib.sha256(f"{user.user_id}:{user.id}".encode()).hexdigest()[:4]

user.is_deleted = 1
user.deleted_at = utc_now_naive()
Expand Down Expand Up @@ -826,3 +837,36 @@ async def impersonate_user(
"department_id": target_user.department_id,
"department_name": department_name,
}


# =============================================================================
# === OIDC 认证分组 ===
# =============================================================================

@auth.get("/oidc/config", response_model=OIDCConfigResponse)
async def get_oidc_config():
"""获取 OIDC 配置(供前端使用)"""
return await get_oidc_config_handler()


@auth.get("/oidc/login-url")
async def get_oidc_login_url(redirect_path: str = "/"):
"""获取 OIDC 登录 URL"""
return await oidc_login_url_handler(redirect_path)


@auth.get("/oidc/callback", response_class=RedirectResponse)
async def oidc_callback(
request: Request,
code: str,
state: str,
db: AsyncSession = Depends(get_db)
):
"""处理 OIDC 回调 - 重定向到前端 Vue 路由"""
return await oidc_callback_handler(code, state, db, request)


@auth.post("/oidc/exchange-code", response_model=OIDCLoginResponse)
async def oidc_exchange_code(code: str = Body(..., embed=True)):
"""使用一次性 code 交换 OIDC 登录数据"""
return await oidc_exchange_code_handler(code)
Comment thread
DSYZayn marked this conversation as resolved.
Comment thread
DSYZayn marked this conversation as resolved.
Loading
Loading