Merge pull request #79 from hamster1963/refactor-auth

refactor: auth page
This commit is contained in:
仓鼠 2024-10-21 10:17:00 +08:00 committed by GitHub
commit f2b47d5cbf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 97 additions and 62 deletions

View File

@ -63,7 +63,7 @@ function Header() {
// https://github.com/streamich/react-use/blob/master/src/useInterval.ts // https://github.com/streamich/react-use/blob/master/src/useInterval.ts
const useInterval = (callback: Function, delay?: number | null) => { const useInterval = (callback: Function, delay?: number | null) => {
const savedCallback = useRef<Function>(() => { }); const savedCallback = useRef<Function>(() => {});
useEffect(() => { useEffect(() => {
savedCallback.current = callback; savedCallback.current = callback;
}); });
@ -98,7 +98,9 @@ function Overview() {
</p> </p>
{mouted ? ( {mouted ? (
<p className="opacity-1 text-sm font-medium">{timeString}</p> <p className="opacity-1 text-sm font-medium">{timeString}</p>
) : <Skeleton className="h-[20px] w-[50px] rounded-[5px] bg-muted-foreground/10 animate-none"></Skeleton>} ) : (
<Skeleton className="h-[20px] w-[50px] rounded-[5px] bg-muted-foreground/10 animate-none"></Skeleton>
)}
</div> </div>
</section> </section>
); );

View File

@ -1,7 +1,7 @@
import Footer from "@/app/[locale]/(main)/footer"; import Footer from "@/app/[locale]/(main)/footer";
import Header from "@/app/[locale]/(main)/header"; import Header from "@/app/[locale]/(main)/header";
import { auth } from "@/auth"; import { auth } from "@/auth";
import { SignIn } from "@/components/sign-in"; import { SignIn } from "@/components/SignIn";
import getEnv from "@/lib/env-entry"; import getEnv from "@/lib/env-entry";
import { redirect } from "next/navigation"; import { redirect } from "next/navigation";
import React from "react"; import React from "react";
@ -13,11 +13,7 @@ export default async function MainLayout({ children }: DashboardProps) {
const session = await auth(); const session = await auth();
if (!session && getEnv("SitePassword")) { if (!session && getEnv("SitePassword")) {
if (getEnv("CF_PAGES")) { return <SignIn />;
redirect("/api/auth/signin");
} else {
return <SignIn />;
}
} }
return ( return (

View File

@ -6,14 +6,15 @@ import getEnv from "./lib/env-entry";
export const { handlers, signIn, signOut, auth } = NextAuth({ export const { handlers, signIn, signOut, auth } = NextAuth({
secret: "this_is_nezha_dash_web_secret", secret: "this_is_nezha_dash_web_secret",
trustHost: true, trustHost: true,
pages: {
signIn: "/",
},
providers: [ providers: [
Credentials({ Credentials({
credentials: { credentials: { password: { label: "Password", type: "password" } },
password: {},
},
authorize: async (credentials) => { authorize: async (credentials) => {
if (credentials.password === getEnv("SitePassword")) { if (credentials.password === getEnv("SitePassword")) {
return { id: "0" }; return { id: "nezha-dash-auth" };
} }
return null; return null;
}, },

66
components/SignIn.tsx Normal file
View File

@ -0,0 +1,66 @@
"use client";
import Footer from "@/app/[locale]/(main)/footer";
import Header from "@/app/[locale]/(main)/header";
import { getCsrfToken } from "next-auth/react";
import { useTranslations } from "next-intl";
import { useSearchParams } from "next/navigation";
import { useEffect, useState } from "react";
export function SignIn({}) {
const t = useTranslations("SignIn");
const [csrfToken, setCsrfToken] = useState("");
const [errorState, setErrorState] = useState(false);
const search = useSearchParams();
const error = search.get("error");
useEffect(() => {
if (error) {
setErrorState(true);
}
}, [error]);
useEffect(() => {
async function loadProviders() {
const csrf = await getCsrfToken();
setCsrfToken(csrf);
}
loadProviders();
}, []);
return (
<div className="flex min-h-screen w-full flex-col">
<main className="flex min-h-[calc(100vh_-_theme(spacing.16))] flex-1 flex-col gap-4 bg-muted/40 p-4 md:p-10 md:pt-8">
<Header />
<form
className="flex flex-col items-center justify-start gap-4 p-4 "
method="post"
action="/api/auth/callback/credentials"
>
<input type="hidden" name="csrfToken" value={csrfToken} />
<section className="flex flex-col items-start gap-2">
<label className="flex flex-col items-start gap-1 ">
{errorState && (
<p className="text-red-500 text-sm font-semibold">
{t("ErrorMessage")}
</p>
)}
<p className="text-base font-semibold">{t("SignInMessage")}</p>
<input
className="px-1 border-[1px] rounded-[5px]"
name="password"
type="password"
/>
</label>
<button className=" px-1.5 py-0.5 w-fit text-sm font-semibold rounded-[8px] border bg-card hover:brightness-95 transition-all text-card-foreground shadow-lg shadow-neutral-200/40 dark:shadow-none">
{t("Submit")}
</button>
</section>
</form>
<Footer />
</main>
</div>
);
}

View File

@ -1,45 +0,0 @@
import Footer from "@/app/[locale]/(main)/footer";
import Header from "@/app/[locale]/(main)/header";
import { signIn } from "@/auth";
import { useLocale } from "next-intl";
import { redirect } from "next/navigation";
export function SignIn() {
const locale = useLocale();
async function handleSubmit(formData: FormData) {
"use server";
try {
await signIn("credentials", formData);
} catch (error) {
redirect(`/${locale}`);
}
}
return (
<div className="flex min-h-screen w-full flex-col">
<main className="flex min-h-[calc(100vh_-_theme(spacing.16))] flex-1 flex-col gap-4 bg-muted/40 p-4 md:p-10 md:pt-8">
<Header />
<form
className="flex flex-col items-center justify-start gap-4 p-4 "
action={handleSubmit}
>
<section className="flex flex-col items-start gap-2">
<label className="flex flex-col items-start gap-1 ">
<p className="text-base font-semibold"></p>
<input
className="px-1 border-[1px] rounded-[5px]"
name="password"
type="password"
/>
</label>
<button className=" px-1.5 py-0.5 w-fit text-sm font-semibold rounded-[8px] border bg-card hover:brightness-95 transition-all text-card-foreground shadow-lg shadow-neutral-200/40 dark:shadow-none">
</button>
</section>
</form>
<Footer />
</main>
</div>
);
}

View File

@ -23,6 +23,11 @@
"Detail": "Detail", "Detail": "Detail",
"Network": "Network" "Network": "Network"
}, },
"SignIn": {
"SignInMessage": "Please enter the password",
"Submit": "Login",
"ErrorMessage": "Invalid password"
},
"ServerCardPopover": { "ServerCardPopover": {
"System": "System", "System": "System",
"CPU": "CPU", "CPU": "CPU",

View File

@ -23,6 +23,11 @@
"Detail": "詳細", "Detail": "詳細",
"Network": "ネットワーク" "Network": "ネットワーク"
}, },
"SignIn": {
"SignInMessage": "パスワードを入力してください",
"Submit": "ログイン",
"ErrorMessage": "パスワードが間違っています"
},
"ServerCardPopover": { "ServerCardPopover": {
"System": "システム", "System": "システム",
"CPU": "CPU", "CPU": "CPU",

View File

@ -23,6 +23,11 @@
"Detail": "詳細", "Detail": "詳細",
"Network": "網路" "Network": "網路"
}, },
"SignIn": {
"SignInMessage": "請輸入密碼",
"Submit": "登入",
"ErrorMessage": "密碼錯誤"
},
"ServerCardPopover": { "ServerCardPopover": {
"System": "系統", "System": "系統",
"CPU": "CPU", "CPU": "CPU",

View File

@ -23,6 +23,11 @@
"Detail": "详情", "Detail": "详情",
"Network": "网络" "Network": "网络"
}, },
"SignIn": {
"SignInMessage": "请输入密码",
"Submit": "登录",
"ErrorMessage": "密码错误"
},
"ServerCardPopover": { "ServerCardPopover": {
"System": "系统", "System": "系统",
"CPU": "CPU", "CPU": "CPU",

View File

@ -23,11 +23,6 @@ const withPWA = withPWAInit({
const nextConfig = { const nextConfig = {
output: "standalone", output: "standalone",
reactStrictMode: true, reactStrictMode: true,
experimental: {
serverActions: {
allowedOrigins: ["*"],
},
},
logging: { logging: {
fetches: { fetches: {
fullUrl: true, fullUrl: true,