import { type LoaderFunctionArgs, redirect } from "@remix-run/node"; import { OAuthClient } from "~/api/login/oauth-client"; import { OAUTH_CONFIG } from "~/config/api-config"; import { createUserSession, saveUserInfo } from "~/api/login/auth.server"; import { JWTUtils, type UserInfoForJWT } from "~/utils/jwt"; import { toastService } from "~/components/ui"; export async function loader({ request }: LoaderFunctionArgs) { const url = new URL(request.url); const code = url.searchParams.get("code"); // const state = url.searchParams.get("state"); const error = url.searchParams.get("error"); const error_description = url.searchParams.get("error_description"); // 检查是否有错误 if (error) { console.error("OAuth2.0授权失败:", error, error_description); return redirect(`/login?error=${encodeURIComponent(error_description || error)}`); } // 检查是否有授权码 if (!code) { toastService.error("通过OAuth2.0登录回调缺少授权码"); console.error("OAuth2.0回调缺少授权码"); return redirect("/login?error=missing_code"); } // 验证状态值(可选,但建议实现) // 这里简单验证state是否以_idp结尾 // if (!state || !state.endsWith("_idp")) { // console.error("OAuth2.0状态值验证失败"); // return redirect("/login?error=invalid_state"); // } try { // 创建OAuth客户端 const oauthClient = new OAuthClient(OAUTH_CONFIG); // 获取访问令牌 const tokenResponse = await oauthClient.getAccessToken(code); if (!tokenResponse) { console.error("获取访问令牌失败"); return redirect("/login?error=token_error"); } // 获取用户信息 const userInfo = await oauthClient.getUserInfo(tokenResponse.access_token); if (!userInfo || !userInfo.success) { console.error("获取用户信息失败:", userInfo); return redirect("/login?error=userinfo_error"); } // TODO 根据用户信息判断用户角色,这里可以根据实际业务逻辑调整 暂定都是common // const userRole = userInfo.data.username === "admin" ? "developer" : "common"; const userRole = "common"; // 获取重定向URL const redirectTo = url.searchParams.get("redirect") || "/"; // 成功获取用户信息之后通过auth.server.ts中的saveUserInfo方法去写入自己的数据库中,通过sub作为唯一值去添加数据 const saveResult = await saveUserInfo(userInfo.data); if (!saveResult.success) { console.error("保存用户信息到数据库失败:", saveResult.error); // 注意:即使保存到数据库失败,我们仍然继续登录流程,因为用户已经通过了身份验证 return redirect("/login?error=save_user_error"); } console.log("用户信息已成功保存到数据库"); const savedUserData = saveResult.data!; // 生成前端专用JWT const jwtUserInfo: UserInfoForJWT = { sub: userInfo.data.sub, user_id: savedUserData.id!, username: savedUserData.username, nick_name: savedUserData.nick_name, email: savedUserData.email, phone_number: savedUserData.phone_number, ou_id: savedUserData.ou_id, ou_name: savedUserData.ou_name, is_leader: savedUserData.is_leader, user_role: userRole }; const frontendJWT = JWTUtils.generateJWT(jwtUserInfo, tokenResponse.expires_in); console.log("前端JWT已生成"); // 更新userInfo以包含数据库ID和JWT信息 const enhancedUserInfo = { ...userInfo.data, user_id: savedUserData.id, user_role: userRole, frontend_jwt: frontendJWT }; // 使用统一的session创建函数 return createUserSession({ isAuthenticated: true, userRole: userRole as 'common' | 'developer', redirectTo, accessToken: tokenResponse.access_token, refreshToken: tokenResponse.refresh_token, tokenExpiresIn: tokenResponse.expires_in, userInfo: enhancedUserInfo, frontendJWT }); } catch (error) { console.error("OAuth2.0回调处理失败:", error); return redirect("/login?error=callback_error"); } } export default function Callback() { return (

正在处理登录...

); }