给所有请求都加上jwt,隐藏生成jwt的secret(放到.env中),隐藏app-secret(放在pm2运行配置文件中,后续直接读取环境配置即可)
This commit is contained in:
+44
-15
@@ -1,7 +1,21 @@
|
||||
import { type LoaderFunctionArgs, redirect } from "@remix-run/node";
|
||||
import { createUserSession, saveUserInfo } from "~/api/login/auth.server";
|
||||
import { createUserSession, saveUserInfo, sessionStorage } from "~/api/login/auth.server";
|
||||
import { JWTUtils, type UserInfoForJWT } from "~/utils/jwt";
|
||||
|
||||
/**
|
||||
* 辅助函数:使用 session flash 重定向到登录页面并传递错误信息
|
||||
*/
|
||||
async function redirectToLoginWithError(request: Request, errorMessage: string) {
|
||||
const session = await sessionStorage.getSession(request.headers.get("Cookie"));
|
||||
session.flash("loginError", errorMessage);
|
||||
|
||||
return redirect("/login", {
|
||||
headers: {
|
||||
"Set-Cookie": await sessionStorage.commitSession(session)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export async function loader({ request }: LoaderFunctionArgs) {
|
||||
const url = new URL(request.url);
|
||||
const origin = url.origin; // 获取请求的源 (e.g., "http://10.79.97.17:51703")
|
||||
@@ -21,19 +35,19 @@ export async function loader({ request }: LoaderFunctionArgs) {
|
||||
// 检查是否有错误
|
||||
if (error) {
|
||||
console.error("❌ OAuth2.0授权失败:", error, error_description);
|
||||
return redirect(`/login?error=${encodeURIComponent(error_description || error)}`);
|
||||
return redirectToLoginWithError(request, error_description || error || "授权失败");
|
||||
}
|
||||
|
||||
// 检查是否有授权码
|
||||
if (!code) {
|
||||
console.error("❌ OAuth2.0回调缺少授权码");
|
||||
return redirect("/login?error=missing_code");
|
||||
return redirectToLoginWithError(request, "登录过程中缺少授权码,请重新登录");
|
||||
}
|
||||
|
||||
// 验证状态值
|
||||
if (!state || !state.endsWith("_idp")) {
|
||||
console.error("❌ OAuth2.0状态值验证失败:", { state, expectedSuffix: "_idp" });
|
||||
return redirect("/login?error=invalid_state");
|
||||
return redirectToLoginWithError(request, "登录状态验证失败,请重新登录");
|
||||
}
|
||||
|
||||
console.log("✅ OAuth2.0回调参数验证通过");
|
||||
@@ -57,7 +71,7 @@ export async function loader({ request }: LoaderFunctionArgs) {
|
||||
|
||||
if (!proxyResponse.ok || !tokenResponse.success) {
|
||||
console.error("❌ [Callback] 通过内部代理获取访问令牌失败:", tokenResponse);
|
||||
return redirect("/login?error=token_proxy_error");
|
||||
return redirectToLoginWithError(request, "获取访问令牌失败,请重新登录");
|
||||
}
|
||||
|
||||
// --- 修改结束 ---
|
||||
@@ -78,7 +92,7 @@ export async function loader({ request }: LoaderFunctionArgs) {
|
||||
|
||||
if (!userInfoProxyResponse.ok || !userInfoResponse.success) {
|
||||
console.error("❌ [Callback] 通过内部代理获取用户信息失败:", userInfoResponse);
|
||||
return redirect("/login?error=userinfo_proxy_error");
|
||||
return redirectToLoginWithError(request, "获取用户信息失败,请重新登录");
|
||||
}
|
||||
|
||||
// 将代理返回的用户信息包装成与原有一致的结构
|
||||
@@ -95,19 +109,34 @@ export async function loader({ request }: LoaderFunctionArgs) {
|
||||
|
||||
// 获取重定向URL
|
||||
const redirectTo = url.searchParams.get("redirect") || "/";
|
||||
|
||||
|
||||
// 先生成一个临时 JWT
|
||||
const tempUserInfo = {
|
||||
sub: userInfo.data.sub,
|
||||
user_id: userInfo.data.user_id || "",
|
||||
username: userInfo.data.username,
|
||||
nick_name: userInfo.data.nick_name,
|
||||
email: userInfo.data.email,
|
||||
phone_number: userInfo.data.phone_number,
|
||||
ou_id: userInfo.data.ou_id,
|
||||
ou_name: userInfo.data.ou_name,
|
||||
is_leader: userInfo.data.is_leader,
|
||||
user_role: userRole as 'common' | 'developer'
|
||||
};
|
||||
const tempToken = JWTUtils.generateJWT(tempUserInfo, tokenResponse.expires_in);
|
||||
|
||||
// 成功获取用户信息之后通过auth.server.ts中的saveUserInfo方法去写入自己的数据库中,通过sub作为唯一值去添加数据
|
||||
const saveResult = await saveUserInfo(userInfo.data);
|
||||
const saveResult = await saveUserInfo(userInfo.data, tempToken);
|
||||
if (!saveResult.success) {
|
||||
console.error("保存用户信息到数据库失败:", saveResult.error);
|
||||
// 注意:即使保存到数据库失败,我们仍然继续登录流程,因为用户已经通过了身份验证
|
||||
return redirect("/login?error=save_user_error");
|
||||
return redirectToLoginWithError(request, "保存用户信息失败,请重新登录");
|
||||
}
|
||||
|
||||
|
||||
console.log("用户信息已成功保存到数据库");
|
||||
const savedUserData = saveResult.data!;
|
||||
|
||||
// 生成前端专用JWT
|
||||
|
||||
// 生成前端专用JWT(使用完整的用户信息,包括数据库 ID)
|
||||
const jwtUserInfo: UserInfoForJWT = {
|
||||
sub: userInfo.data.sub,
|
||||
user_id: savedUserData.id!,
|
||||
@@ -120,7 +149,7 @@ export async function loader({ request }: LoaderFunctionArgs) {
|
||||
is_leader: savedUserData.is_leader,
|
||||
user_role: userRole as 'common' | 'developer'
|
||||
};
|
||||
|
||||
|
||||
const frontendJWT = JWTUtils.generateJWT(jwtUserInfo, tokenResponse.expires_in);
|
||||
console.log("前端JWT已生成");
|
||||
|
||||
@@ -143,7 +172,7 @@ export async function loader({ request }: LoaderFunctionArgs) {
|
||||
// 使用统一的session创建函数
|
||||
return createUserSession({
|
||||
isAuthenticated: true,
|
||||
userRole: userRole as 'common' | 'developer',
|
||||
userRole: userRole,
|
||||
redirectTo,
|
||||
accessToken: tokenResponse.access_token,
|
||||
refreshToken: tokenResponse.refresh_token,
|
||||
@@ -154,7 +183,7 @@ export async function loader({ request }: LoaderFunctionArgs) {
|
||||
|
||||
} catch (error) {
|
||||
console.error("OAuth2.0回调处理失败:", error);
|
||||
return redirect("/login?error=callback_error");
|
||||
return redirectToLoginWithError(request, "登录回调处理失败,请重新登录");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user