2023-10-26

RemixJS 2 保有登入狀態

RemixJS 2 保有登入狀態

呈上篇 RemixJS 2 以 session 實作登入機制,session 的資料存放在 cookie 裡,那要如何在頁面內判斷及保有登入的狀態?

在前端可以用原本 react 的處理方式,以 context 來保有狀態。在後端必須每個 request 都要檢查 cookie。

get-auth.ts 是將解讀 cookie 的功能寫成模組,用來判斷是否為登入狀態。

// app/modules/get-auth.ts import { getMySession } from "~/modules/sessions"; async function getAuth(request: Request) { const session = await getMySession(request); const userId = session.get("userId") || ""; const nickname = session.get("nickname") || ""; return { userId, nickname, auth: !!userId }; // auth 屬性用來判斷是否登入 } export default getAuth;

AuthContextProvider

// app/contexts/AuthContext.tsx import React, { createContext } from "react"; export type AuthDataType = { userId: string | undefined; nickname: string | undefined; }; export const AuthContext = createContext<AuthDataType>({ userId: "", nickname: "", }); type PropsType = { userId: string | undefined; nickname: string | undefined; children: React.ReactNode; }; export function AuthContextProvider({ userId, nickname, children }: PropsType) { return ( <AuthContext.Provider value={{ userId, nickname }}> {children} </AuthContext.Provider> ); }

<AuthContextProvider> 包住 <Outlet />

// app/root.tsx 部份內容 export async function loader({ request, params }: LoaderFunctionArgs) { console.log("App loader"); return await getAuth(request); } export default function App() { const loaderData = useLoaderData<typeof loader>() return ( <html lang="en"> <head> <meta charSet="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <Meta /> <Links /> </head> <body> <AuthContextProvider userId={loaderData.userId} nickname={loaderData.nickname}> <Outlet /> </AuthContextProvider> <ScrollRestoration /> <Scripts /> <LiveReload /> </body> </html> ); }

防止未授權而使用功能

這裡要分兩個部份 loader 和 action。loader 因為有階層關係,可以在 Layout 的 loader 做阻擋的動作。

// app/routes/address-book.tsx 的 loader 部份 export async function loader({ request, params }: LoaderFunctionArgs) { console.log("address-book loader"); const myAuth = await getAuth(request); if (!myAuth.auth) { // 沒有登入,轉到登入頁面 return redirect(`/login?u=${request.url}`); } return null; }

action 就必須在每個頁面處理。

export async function action({ request, params }: ActionFunctionArgs) { const myAuth = await getAuth(request); if (!myAuth.auth) { // 沒有登入,轉到登入頁面 return redirect(`/login?u=${request.url}`); } // 略 }

沒有留言:

FB 留言