优化登录逻辑的实现,将认证请求和token验证的处理分成两个逻辑文件。新增交叉评查任务列表的页面(尚未对接真实数据)。
This commit is contained in:
+20
-88
@@ -14,7 +14,6 @@ import {
|
||||
import {
|
||||
LoaderFunctionArgs,
|
||||
redirect,
|
||||
createCookieSessionStorage,
|
||||
ActionFunctionArgs
|
||||
} from "@remix-run/node";
|
||||
import { Layout } from "~/components/layout/Layout";
|
||||
@@ -30,8 +29,14 @@ import LoadingBarContainer from "~/components/ui/LoadingBar";
|
||||
import RouteChangeLoader from "~/components/ui/RouteChangeLoader";
|
||||
// import { useState, useEffect } from "react";
|
||||
|
||||
// 定义用户角色类型
|
||||
export type UserRole = 'common' | 'developer';
|
||||
// 导入认证相关的服务器端功能(仅在服务器端使用)
|
||||
import {
|
||||
getUserSession,
|
||||
getSession,
|
||||
sessionStorage,
|
||||
logout,
|
||||
type UserRole
|
||||
} from "~/api/login/auth.server";
|
||||
|
||||
// 定义需要高级权限的路径
|
||||
export const developerOnlyPaths = [
|
||||
@@ -41,91 +46,10 @@ export const developerOnlyPaths = [
|
||||
'/prompts',
|
||||
];
|
||||
|
||||
// 创建基于Cookie的会话存储
|
||||
// 在实际应用中,应该使用环境变量来设置密钥
|
||||
export const sessionStorage = createCookieSessionStorage({
|
||||
cookie: {
|
||||
name: "__lgsession",
|
||||
httpOnly: true,
|
||||
path: "/",
|
||||
sameSite: "lax",
|
||||
secrets: ["s3cr3t"], // 应该从环境变量读取
|
||||
// secure: process.env.NODE_ENV === "production",
|
||||
maxAge: 60 * 60 * 24 * 1, // 1天
|
||||
secure: false, // 开发环境中禁用secure
|
||||
},
|
||||
});
|
||||
// 导出类型供客户端使用
|
||||
export type { UserRole };
|
||||
|
||||
// 获取会话对象
|
||||
export async function getSession(request: Request) {
|
||||
const cookie = request.headers.get("Cookie");
|
||||
return sessionStorage.getSession(cookie);
|
||||
}
|
||||
|
||||
// 获取用户登录状态
|
||||
export async function getUserSession(request: Request) {
|
||||
const session = await getSession(request);
|
||||
const isAuthenticated = session.get("isAuthenticated") === true;
|
||||
const userRole = session.get("userRole") || 'common' as UserRole;
|
||||
const accessToken = session.get("accessToken");
|
||||
const refreshToken = session.get("refreshToken");
|
||||
const tokenIssuedAt = session.get("tokenIssuedAt");
|
||||
const tokenExpiresIn = session.get("tokenExpiresIn");
|
||||
const userInfo = session.get("userInfo");
|
||||
|
||||
// 检查token是否过期
|
||||
let isTokenExpired = false;
|
||||
if (accessToken && tokenIssuedAt && tokenExpiresIn) {
|
||||
const now = Date.now();
|
||||
const expiresAt = tokenIssuedAt + (tokenExpiresIn * 1000);
|
||||
isTokenExpired = now >= expiresAt;
|
||||
}
|
||||
|
||||
// console.log("获取会话状态:",
|
||||
// // "Cookie:", request.headers.get("Cookie"),
|
||||
// "是否认证:", isAuthenticated,
|
||||
// "用户角色:", userRole,
|
||||
// "Token过期:", isTokenExpired
|
||||
// );
|
||||
|
||||
return {
|
||||
isAuthenticated: isAuthenticated && !isTokenExpired,
|
||||
userRole,
|
||||
accessToken,
|
||||
refreshToken,
|
||||
userInfo,
|
||||
isTokenExpired
|
||||
};
|
||||
}
|
||||
|
||||
// 创建登录会话
|
||||
export async function createUserSession(isAuthenticated: boolean, userRole: UserRole, redirectTo: string) {
|
||||
const session = await sessionStorage.getSession();
|
||||
session.set("isAuthenticated", isAuthenticated);
|
||||
session.set("userRole", userRole);
|
||||
|
||||
const cookie = await sessionStorage.commitSession(session);
|
||||
console.log("创建会话 - 设置Cookie:", !!cookie);
|
||||
console.log("创建会话 - 用户角色:", userRole);
|
||||
console.log("创建会话 - 重定向到:", redirectTo);
|
||||
|
||||
return redirect(redirectTo, {
|
||||
headers: {
|
||||
"Set-Cookie": cookie,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// 销毁会话(登出)
|
||||
export async function logout(request: Request) {
|
||||
const session = await getSession(request);
|
||||
|
||||
return redirect("/login", {
|
||||
headers: {
|
||||
"Set-Cookie": await sessionStorage.destroySession(session),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// 添加action处理登录/登出请求
|
||||
export async function action({ request }: ActionFunctionArgs) {
|
||||
@@ -149,8 +73,8 @@ export async function loader({ request }: LoaderFunctionArgs) {
|
||||
const publicPaths = ['/login', '/favicon.ico'];
|
||||
const isPublicPath = publicPaths.some(path => pathname.startsWith(path));
|
||||
|
||||
// 获取用户会话
|
||||
const { isAuthenticated, userRole } = await getUserSession(request);
|
||||
// 获取用户会话(可能包含刷新后的token)
|
||||
const { isAuthenticated, userRole, refreshedSession } = await getUserSession(request);
|
||||
// console.log("是否公开路径:", isPublicPath, "是否已认证:", isAuthenticated);
|
||||
|
||||
// 如果访问需要认证的路径但未登录,重定向到登录页
|
||||
@@ -184,6 +108,12 @@ export async function loader({ request }: LoaderFunctionArgs) {
|
||||
return redirect("/");
|
||||
}
|
||||
|
||||
// 如果token被刷新了,需要在响应中设置更新后的cookie
|
||||
const responseHeaders: Record<string, string> = {};
|
||||
if (refreshedSession) {
|
||||
responseHeaders["Set-Cookie"] = await sessionStorage.commitSession(refreshedSession);
|
||||
}
|
||||
|
||||
// 向组件传递认证状态、当前路径和环境变量
|
||||
return Response.json({
|
||||
isAuthenticated,
|
||||
@@ -194,6 +124,8 @@ export async function loader({ request }: LoaderFunctionArgs) {
|
||||
NEXT_PUBLIC_APP_ID: process.env.NEXT_PUBLIC_APP_ID,
|
||||
NEXT_PUBLIC_APP_KEY: process.env.NEXT_PUBLIC_APP_KEY,
|
||||
},
|
||||
}, {
|
||||
headers: responseHeaders
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user