import { type ActionFunctionArgs, json } from "@remix-run/node"; import { OAuthClient } from "~/api/login/oauth-client"; import { getServerOAuthConfigRuntime } from "~/config/oauth-secret.server"; /** * 这个Action作为获取OAuth Access Token的服务器端代理。 * 它接收来自前端回调的`code`,然后在后端安全地换取令牌, * 以避免在网络策略限制服务器直接访问外部服务时出现问题。 */ export async function action({ request }: ActionFunctionArgs) { // 1. 只允许POST请求 if (request.method !== "POST") { return json({ success: false, error: "Method Not Allowed" }, { status: 405 }); } try { // 2. 从请求体中获取`code` const { code } = await request.json(); if (!code || typeof code !== 'string') { return json({ success: false, error: "Missing or invalid 'code' in request body" }, { status: 400 }); } console.log("🔧 [/api/oauth/token] 收到代理请求, code:", code ? `${code.substring(0, 10)}...` : null); // 3. 在服务器端使用OAuthClient安全地获取访问令牌 // 🔒 安全:从 .server.ts 文件运行时读取配置,确保环境变量正确加载 const oauthClient = new OAuthClient(getServerOAuthConfigRuntime()); const tokenResponse = await oauthClient.getAccessToken(code); // 4. 处理来自IDaaS服务器的响应 if (!tokenResponse) { console.error("❌ [/api/oauth/token] 从IDaaS获取访问令牌失败。"); // 502 Bad Gateway 表示上游服务器(IDaaS)响应无效 return json({ success: false, error: "Failed to get access token from IDaaS" }, { status: 502 }); } console.log("✅ [/api/oauth/token] 已通过代理成功获取令牌。"); // 5. 将成功的令牌响应返回给调用方 (callback.tsx) return json({ success: true, ...tokenResponse }); } catch (error) { console.error("❌ [/api/oauth/token] 代理API发生意外错误:", error); const errorMessage = error instanceof Error ? error.message : "An unknown error occurred."; return json({ success: false, error: "Proxy internal error", details: errorMessage }, { status: 500 }); } }