fix: 完善单点登录传递回调地址和serverUrl的功能。优化token刷新机制,判断单点登录和管理员登录等等不同路径的处理机制。提示词管理的模板数据查找的时候只需要返回固定的5个类型。隐藏评查点设置中关于抽取的自定义模板的选择。
This commit is contained in:
+55
-7
@@ -1,7 +1,7 @@
|
||||
import { type LoaderFunctionArgs, redirect } from "@remix-run/node";
|
||||
import { createUserSession, saveUserInfo, sessionStorage } from "~/api/login/auth.server";
|
||||
import { OAuthClient } from "~/api/login/oauth-client";
|
||||
import { OAUTH_CONFIG } from "~/config/api-config";
|
||||
import { getServerOAuthConfigRuntime } from "~/config/oauth-secret.server";
|
||||
import { JWTUtils, type UserInfoForJWT } from "~/utils/jwt";
|
||||
|
||||
/**
|
||||
@@ -79,16 +79,20 @@ export async function loader({ request }: LoaderFunctionArgs) {
|
||||
|
||||
console.log("✅ OAuth2.0回调参数验证通过");
|
||||
|
||||
// 声明在 try 外部,以便在 catch 中访问
|
||||
let tokenResponse = null;
|
||||
const oauthClient = new OAuthClient(getServerOAuthConfigRuntime());
|
||||
|
||||
try {
|
||||
console.log("🔧 开始处理OAuth2.0回调");
|
||||
|
||||
const oauthClient = new OAuthClient(OAUTH_CONFIG)
|
||||
|
||||
// 开始获取访问令牌
|
||||
const tokenResponse = await oauthClient.getAccessToken(code);
|
||||
tokenResponse = await oauthClient.getAccessToken(code);
|
||||
if (!tokenResponse) {
|
||||
console.error("获取访问令牌失败");
|
||||
return redirect("/login?error=token_error")
|
||||
// 注意:此时还没有 access_token,无法调用 IDaaS 登出
|
||||
// 只能重定向到登录页,让用户重新开始登录流程
|
||||
return redirectToLoginWithError(request, "获取访问令牌失败,请重试");
|
||||
}
|
||||
console.log("✅ [Callback] 访问令牌获取成功");
|
||||
|
||||
@@ -96,7 +100,22 @@ export async function loader({ request }: LoaderFunctionArgs) {
|
||||
const userInfo = await oauthClient.getUserInfo(tokenResponse.access_token);
|
||||
if(!userInfo || !userInfo.success){
|
||||
console.error('获取用户信息失败:',userInfo);
|
||||
return redirect('/login?error=userinfo_error')
|
||||
|
||||
// 🔑 关键:此时 IDaaS 那边已经登录成功,但我们获取用户信息失败
|
||||
// 需要调用 IDaaS 登出,清除 IDaaS 的登录状态,避免用户下次登录时出现问题
|
||||
try {
|
||||
const logoutUrl = `${url.protocol}//${url.host}/login`;
|
||||
const logoutSuccess = await oauthClient.logout(tokenResponse.access_token, logoutUrl);
|
||||
if (logoutSuccess) {
|
||||
console.log("✅ [Callback] 已清除 IDaaS 登录状态");
|
||||
} else {
|
||||
console.warn("⚠️ [Callback] 清除 IDaaS 登录状态失败");
|
||||
}
|
||||
} catch (logoutError) {
|
||||
console.error("❌ [Callback] 调用 IDaaS 登出时出错:", logoutError);
|
||||
}
|
||||
|
||||
return redirectToLoginWithError(request, "获取用户信息失败,请重试");
|
||||
}
|
||||
console.log("✅ [Callback] 用户信息获取成功");
|
||||
|
||||
@@ -128,7 +147,20 @@ export async function loader({ request }: LoaderFunctionArgs) {
|
||||
const saveResult = await saveUserInfo(userInfo.data, tempToken, area);
|
||||
if (!saveResult.success) {
|
||||
console.error("保存用户信息到数据库失败:", saveResult.error);
|
||||
// 注意:即使保存到数据库失败,我们仍然继续登录流程,因为用户已经通过了身份验证
|
||||
|
||||
// 🔑 保存用户信息失败,需要清除 IDaaS 登录状态
|
||||
try {
|
||||
const logoutUrl = `${url.protocol}//${url.host}/login`;
|
||||
const logoutSuccess = await oauthClient.logout(tokenResponse.access_token, logoutUrl);
|
||||
if (logoutSuccess) {
|
||||
console.log("✅ [Callback] 已清除 IDaaS 登录状态(数据库保存失败)");
|
||||
} else {
|
||||
console.warn("⚠️ [Callback] 清除 IDaaS 登录状态失败(数据库保存失败)");
|
||||
}
|
||||
} catch (logoutError) {
|
||||
console.error("❌ [Callback] 调用 IDaaS 登出时出错(数据库保存失败):", logoutError);
|
||||
}
|
||||
|
||||
return redirectToLoginWithError(request, "保存用户信息失败,请重新登录");
|
||||
}
|
||||
|
||||
@@ -182,6 +214,22 @@ export async function loader({ request }: LoaderFunctionArgs) {
|
||||
|
||||
} catch (error) {
|
||||
console.error("OAuth2.0回调处理失败:", error);
|
||||
|
||||
// 🔑 如果已经获取到了 access_token,需要清除 IDaaS 登录状态
|
||||
if (tokenResponse?.access_token) {
|
||||
try {
|
||||
const logoutUrl = `${url.protocol}//${url.host}/login`;
|
||||
const logoutSuccess = await oauthClient.logout(tokenResponse.access_token, logoutUrl);
|
||||
if (logoutSuccess) {
|
||||
console.log("✅ [Callback] 已清除 IDaaS 登录状态(回调处理异常)");
|
||||
} else {
|
||||
console.warn("⚠️ [Callback] 清除 IDaaS 登录状态失败(回调处理异常)");
|
||||
}
|
||||
} catch (logoutError) {
|
||||
console.error("❌ [Callback] 调用 IDaaS 登出时出错(回调处理异常):", logoutError);
|
||||
}
|
||||
}
|
||||
|
||||
return redirectToLoginWithError(request, "登录回调处理失败,请重新登录");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import { useEffect, useState } from "react";
|
||||
import { useActionData, useLoaderData, Form } from "@remix-run/react";
|
||||
import { type MetaFunction, type LoaderFunctionArgs, type ActionFunctionArgs, redirect } from "@remix-run/node";
|
||||
import { OAuthClient } from "~/api/login/oauth-client";
|
||||
import { OAUTH_CONFIG } from "~/config/api-config";
|
||||
import { CLIENT_OAUTH_CONFIG } from "~/config/api-config";
|
||||
import { getUserSession, getSession, simpleRootLogin } from "~/api/login/auth.server";
|
||||
import styles from "~/styles/pages/login.css?url";
|
||||
import { toastService } from "~/components/ui";
|
||||
@@ -114,8 +114,8 @@ export default function Login() {
|
||||
// 处理OAuth2.0登录
|
||||
const handleOAuthLogin = () => {
|
||||
try {
|
||||
// 创建OAuth客户端
|
||||
const oauthClient = new OAuthClient(OAUTH_CONFIG);
|
||||
// 创建OAuth客户端(使用客户端安全配置,不包含 clientSecret)
|
||||
const oauthClient = new OAuthClient(CLIENT_OAUTH_CONFIG);
|
||||
|
||||
// 生成状态值
|
||||
const state = oauthClient.generateState();
|
||||
@@ -172,9 +172,9 @@ export default function Login() {
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
// 检查OAuth配置是否完整
|
||||
if (!OAUTH_CONFIG.serverUrl || !OAUTH_CONFIG.clientId || !OAUTH_CONFIG.clientSecret) {
|
||||
console.error("OAuth2.0配置不完整:", OAUTH_CONFIG);
|
||||
// 检查OAuth配置是否完整(客户端不需要检查 clientSecret)
|
||||
if (!CLIENT_OAUTH_CONFIG.serverUrl || !CLIENT_OAUTH_CONFIG.clientId) {
|
||||
console.error("OAuth2.0配置不完整:", CLIENT_OAUTH_CONFIG);
|
||||
}
|
||||
}, []);
|
||||
|
||||
|
||||
+18
-12
@@ -1,37 +1,43 @@
|
||||
import { type LoaderFunctionArgs, redirect } from "@remix-run/node";
|
||||
import { OAuthClient } from "~/api/login/oauth-client";
|
||||
import { OAUTH_CONFIG } from "~/config/api-config";
|
||||
import { getServerOAuthConfigRuntime } from "~/config/oauth-secret.server";
|
||||
import { sessionStorage } from "~/api/login/auth.server";
|
||||
|
||||
export async function loader({ request }: LoaderFunctionArgs) {
|
||||
const session = await sessionStorage.getSession(request.headers.get("Cookie"));
|
||||
|
||||
// 获取访问令牌
|
||||
|
||||
// 获取访问令牌和用户角色
|
||||
const accessToken = session.get("accessToken");
|
||||
|
||||
if (accessToken) {
|
||||
const userRole = session.get("userRole");
|
||||
|
||||
// 🔑 只有非 admin 用户才需要调用 IDaaS 单点登出
|
||||
const isAdmin = userRole === 'admin';
|
||||
|
||||
if (accessToken && !isAdmin) {
|
||||
try {
|
||||
// 创建OAuth客户端
|
||||
const oauthClient = new OAuthClient(OAUTH_CONFIG);
|
||||
|
||||
// 🔒 安全:使用服务器端专用函数获取完整配置
|
||||
const oauthClient = new OAuthClient(getServerOAuthConfigRuntime());
|
||||
|
||||
// 构建登出后重定向URL
|
||||
const url = new URL(request.url);
|
||||
const redirectUrl = url.searchParams.get("redirect") || `${url.protocol}//${url.host}/login`;
|
||||
|
||||
|
||||
// 调用IDaaS单点登出
|
||||
const logoutSuccess = await oauthClient.logout(accessToken, redirectUrl);
|
||||
|
||||
|
||||
if (!logoutSuccess) {
|
||||
console.warn("IDaaS单点登出失败,但仍清除本地会话");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("单点登出过程中出错:", error);
|
||||
}
|
||||
} else if (isAdmin) {
|
||||
console.log("admin 用户登出,跳过 IDaaS 单点登出");
|
||||
}
|
||||
|
||||
|
||||
// 无论IDaaS登出是否成功,都清除本地会话
|
||||
const cookie = await sessionStorage.destroySession(session);
|
||||
|
||||
|
||||
return redirect("/login", {
|
||||
headers: {
|
||||
"Set-Cookie": cookie
|
||||
|
||||
@@ -52,7 +52,7 @@ export async function loader({ request }: LoaderFunctionArgs) {
|
||||
const page = parseInt(url.searchParams.get('page') || '1', 10);
|
||||
const pageSize = parseInt(url.searchParams.get('pageSize') || '10', 10);
|
||||
|
||||
// console.log('加载提示词模板参数:', { name, type, status, page, pageSize });
|
||||
// console.log('加载提示词模板参数:', { name, type: typeParam, status, page, pageSize });
|
||||
|
||||
// 从 API 获取数据
|
||||
const result = await getPromptTemplates({
|
||||
|
||||
@@ -372,7 +372,7 @@ export default function RuleNew() {
|
||||
// 添加自定义选项
|
||||
const optionsWithCustom = [
|
||||
...response.data,
|
||||
{ value: 'custom', label: '自定义' }
|
||||
// { value: 'custom', label: '自定义' }
|
||||
];
|
||||
setVlmFieldTypeOptions(optionsWithCustom);
|
||||
} else if (response.error) {
|
||||
|
||||
Reference in New Issue
Block a user