基于 shiy-temp分支修改
This commit is contained in:
+48
-31
@@ -1,20 +1,20 @@
|
||||
// import React from 'react';
|
||||
import {
|
||||
Links,
|
||||
import {
|
||||
Links,
|
||||
// LiveReload, // 不再需要,使用Vite时会与内置HMR冲突
|
||||
Meta,
|
||||
Outlet,
|
||||
Scripts,
|
||||
Meta,
|
||||
Outlet,
|
||||
Scripts,
|
||||
ScrollRestoration,
|
||||
isRouteErrorResponse,
|
||||
useRouteError,
|
||||
type MetaFunction,
|
||||
useLoaderData
|
||||
} from "@remix-run/react";
|
||||
import {
|
||||
LoaderFunctionArgs,
|
||||
redirect,
|
||||
createCookieSessionStorage,
|
||||
import {
|
||||
LoaderFunctionArgs,
|
||||
redirect,
|
||||
createCookieSessionStorage,
|
||||
ActionFunctionArgs
|
||||
} from "@remix-run/node";
|
||||
import { Layout } from "~/components/layout/Layout";
|
||||
@@ -85,7 +85,7 @@ export async function createUserSession(isAuthenticated: boolean, userRole: User
|
||||
// 销毁会话(登出)
|
||||
export async function logout(request: Request) {
|
||||
const session = await getSession(request);
|
||||
|
||||
|
||||
return redirect("/login", {
|
||||
headers: {
|
||||
"Set-Cookie": await sessionStorage.destroySession(session),
|
||||
@@ -97,58 +97,67 @@ export async function logout(request: Request) {
|
||||
export async function action({ request }: ActionFunctionArgs) {
|
||||
const formData = await request.formData();
|
||||
const intent = formData.get("intent");
|
||||
|
||||
|
||||
if (intent === "logout") {
|
||||
return logout(request);
|
||||
}
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// 添加loader函数进行全局认证检查
|
||||
// 添加loader函数进行全局认证检查并传递环境变量给客户端
|
||||
export async function loader({ request }: LoaderFunctionArgs) {
|
||||
// 获取当前路径
|
||||
const url = new URL(request.url);
|
||||
const pathname = url.pathname;
|
||||
|
||||
|
||||
// 排除不需要登录验证的路径
|
||||
const publicPaths = ['/login', '/favicon.ico'];
|
||||
const isPublicPath = publicPaths.some(path => pathname.startsWith(path));
|
||||
|
||||
|
||||
// 获取用户会话
|
||||
const { isAuthenticated, userRole } = await getUserSession(request);
|
||||
// console.log("Auth status:", { isAuthenticated, userRole, pathname });
|
||||
|
||||
|
||||
// 如果访问需要认证的路径但未登录,重定向到登录页
|
||||
if (!isPublicPath && !isAuthenticated) {
|
||||
// 保存请求的URL,以便登录后重定向回来
|
||||
const session = await getSession(request);
|
||||
|
||||
|
||||
// 如果路径是/home,则将重定向目标设置为/
|
||||
const redirectTarget = pathname === "/home" ? "/" : pathname;
|
||||
// 保存重定向目标
|
||||
session.set("redirectTo", redirectTarget);
|
||||
|
||||
|
||||
return redirect("/login", {
|
||||
headers: {
|
||||
"Set-Cookie": await sessionStorage.commitSession(session),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// 如果已登录且访问登录页,重定向到首页
|
||||
if (pathname === "/login" && isAuthenticated) {
|
||||
// console.log("Already authenticated, redirecting from login to /");
|
||||
return redirect("/");
|
||||
}
|
||||
|
||||
|
||||
// 检查访问权限 - 如果是common用户访问了开发者专属页面,重定向到首页
|
||||
if (userRole === 'common' && developerOnlyPaths.some(path => pathname.startsWith(path))) {
|
||||
return redirect("/");
|
||||
}
|
||||
|
||||
// 向组件传递认证状态和当前路径
|
||||
return Response.json({ isAuthenticated, userRole, pathname });
|
||||
|
||||
// 向组件传递认证状态、当前路径和环境变量
|
||||
return Response.json({
|
||||
isAuthenticated,
|
||||
userRole,
|
||||
pathname,
|
||||
ENV: {
|
||||
NEXT_PUBLIC_API_URL: process.env.NEXT_PUBLIC_API_URL,
|
||||
NEXT_PUBLIC_APP_ID: process.env.NEXT_PUBLIC_APP_ID,
|
||||
NEXT_PUBLIC_APP_KEY: process.env.NEXT_PUBLIC_APP_KEY,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -168,6 +177,8 @@ export function links() {
|
||||
{ rel: "stylesheet", href: styles },
|
||||
{ rel: "stylesheet", href: messageModalStyles },
|
||||
{ rel: "stylesheet", href: toastStyles },
|
||||
// 添加 Antd 样式
|
||||
{ rel: "stylesheet", href: "https://cdn.jsdelivr.net/npm/antd@5/dist/reset.css" },
|
||||
{ rel: "icon", type: "image/svg+xml", href: "/logo.svg" },
|
||||
// { rel: "preconnect", href: "https://fonts.googleapis.com" },
|
||||
// { rel: "preconnect", href: "https://fonts.gstatic.com", crossOrigin: "anonymous" },
|
||||
@@ -176,15 +187,16 @@ export function links() {
|
||||
}
|
||||
|
||||
export default function App() {
|
||||
const { userRole } = useLoaderData<typeof loader>();
|
||||
|
||||
|
||||
const { userRole, ENV } = useLoaderData<typeof loader>();
|
||||
|
||||
|
||||
return (
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charSet="utf-8" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||
<style dangerouslySetInnerHTML={{ __html: `
|
||||
<style dangerouslySetInnerHTML={{
|
||||
__html: `
|
||||
:root {
|
||||
--color-primary: #00684a;
|
||||
--color-primary-hover: #005a3f;
|
||||
@@ -199,6 +211,11 @@ export default function App() {
|
||||
` }} />
|
||||
<Meta />
|
||||
<Links />
|
||||
<script
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: `window.__ENV = ${JSON.stringify(ENV)}`,
|
||||
}}
|
||||
/>
|
||||
</head>
|
||||
<body className="font-sans">
|
||||
<MessageModalProvider>
|
||||
@@ -219,11 +236,11 @@ export default function App() {
|
||||
|
||||
export function ErrorBoundary() {
|
||||
const error = useRouteError();
|
||||
|
||||
|
||||
// 为错误页面设置标题和描述
|
||||
let title = "发生错误";
|
||||
let message = "发生了一个未知错误,请稍后重试";
|
||||
|
||||
|
||||
if (isRouteErrorResponse(error)) {
|
||||
title = `错误 ${error.status}`;
|
||||
message = error.data?.message || "发生了一个错误,请稍后重试";
|
||||
@@ -231,7 +248,7 @@ export function ErrorBoundary() {
|
||||
title = "意外错误";
|
||||
message = "服务器发生了意外错误,请稍后重试";
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
@@ -242,7 +259,7 @@ export function ErrorBoundary() {
|
||||
<Links />
|
||||
</head>
|
||||
<body>
|
||||
<AppErrorBoundary
|
||||
<AppErrorBoundary
|
||||
status={isRouteErrorResponse(error) ? error.status : 500}
|
||||
statusText={isRouteErrorResponse(error) ? error.statusText : "服务器错误"}
|
||||
message={message}
|
||||
|
||||
Reference in New Issue
Block a user