-
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Password validation & login and logout
- Loading branch information
1 parent
3307a3f
commit 46d39b0
Showing
19 changed files
with
7,832 additions
and
7,424 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# Default password: 123456 | ||
# Remember to change this password after setting up the app | ||
PASSWORD=14e1b600b1fd579f47433b88e8d85291 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,95 @@ | ||
"use client"; | ||
|
||
import { useEffect } from "react"; | ||
import axios from "axios"; | ||
import md5 from "md5"; | ||
import Cookie from "js-cookie"; | ||
import { Button } from "@nextui-org/button"; | ||
import { Card } from "@nextui-org/card"; | ||
import { Image } from "@nextui-org/image"; | ||
import * as z from "zod"; | ||
import { zodResolver } from "@hookform/resolvers/zod"; | ||
import { useForm } from "react-hook-form"; | ||
import { toast } from "react-toastify"; | ||
import { useRouter } from "next/navigation"; | ||
|
||
import ThemeSwitch from "@/components/theme-switch"; | ||
import PasswordInput from "@/components/password-input"; | ||
import { BaseResponseData } from "@/types"; | ||
import { tokenStorageKey } from "@/lib/global"; | ||
|
||
const schema = z.object({ | ||
password: z.string().min(1, { message: "请输入访问密码" }), | ||
}); | ||
|
||
interface AuthResponseData extends BaseResponseData { | ||
token?: string | ||
} | ||
|
||
export default function Page() { | ||
return <></>; | ||
const router = useRouter(); | ||
const form = useForm({ | ||
resolver: zodResolver(schema), | ||
defaultValues: { | ||
password: "" | ||
} | ||
}); | ||
|
||
const handleLogin = async ({ password }: z.infer<typeof schema>) => { | ||
try { | ||
const { data } = await axios.post<AuthResponseData>("/api/auth", { password: md5(password) }); | ||
const { status, token } = data; | ||
|
||
if(status === 401) throw new Error("访问密码错误"); | ||
if(status === 403) { | ||
router.push("/"); | ||
throw new Error("已登录,无法重复登录"); | ||
} | ||
if(status === 500) throw new Error("服务器错误"); | ||
if(!token) throw new Error("服务器未返回token"); | ||
|
||
Cookie.set(tokenStorageKey, token); | ||
toast.success("登录成功"); | ||
router.push("/x/root"); | ||
} catch (err) { | ||
toast.error("登录失败: "+ err); | ||
} | ||
}; | ||
|
||
useEffect(() => { | ||
if(Cookie.get(tokenStorageKey)) router.push("/"); | ||
}, []); | ||
|
||
return ( | ||
<div className="h-[100vh] flex flex-col justify-center items-center"> | ||
<Card className="w-[500px] h-fit p-6"> | ||
<div className="my-16 flex flex-col items-center cursor-default"> | ||
<Image | ||
alt="logo" | ||
src="/icon.png" | ||
className="w-[70px] mb-4" | ||
style={{ imageRendering: "pixelated" }}/> | ||
<h1 className="font-bold text-2xl mb-2">登录 Ferrum</h1> | ||
<p className=" text-default-400 text-sm">Explore throughout your server.</p> | ||
</div> | ||
|
||
<form className="flex flex-col gap-4" onSubmit={form.handleSubmit(handleLogin)}> | ||
<PasswordInput | ||
{...form.register("password")} | ||
isRequired | ||
label="访问密码" | ||
labelPlacement="outside"/> | ||
<Button color="primary" type="submit"> | ||
登录 | ||
</Button> | ||
</form> | ||
</Card> | ||
|
||
<div className="w-[500px] p-3 flex justify-between"> | ||
<span className="text-default-400 text-sm">Copyright © {new Date().getFullYear()} NoahHrreion</span> | ||
|
||
<ThemeSwitch size="sm"/> | ||
</div> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,15 @@ | ||
import { Metadata } from "next"; | ||
"use client"; | ||
|
||
export const metadata: Metadata = { | ||
title: "仪表盘", | ||
}; | ||
import { useEffect } from "react"; | ||
|
||
import { useDetectCookie } from "@/hooks/useDetectCookie"; | ||
|
||
export default function Page() { | ||
useEffect(() => { | ||
document.title = "Ferrum - 仪表盘"; | ||
}, []); | ||
|
||
useDetectCookie(); | ||
|
||
return <></>; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,15 @@ | ||
import { Metadata } from "next"; | ||
"use client"; | ||
|
||
export const metadata: Metadata = { | ||
title: "设置", | ||
}; | ||
import { useEffect } from "react"; | ||
|
||
import { useDetectCookie } from "@/hooks/useDetectCookie"; | ||
|
||
export default function Page() { | ||
useEffect(() => { | ||
document.title = "Ferrum - 设置"; | ||
}, []); | ||
|
||
useDetectCookie(); | ||
|
||
return <></>; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
/* eslint-disable no-console */ | ||
import { NextRequest, NextResponse } from "next/server"; | ||
import md5 from "md5"; | ||
|
||
import { generateToken } from "@/lib/token"; | ||
import { tokenStorageKey } from "@/lib/global"; | ||
|
||
interface AuthRequestData { | ||
password: string | ||
} | ||
|
||
export async function POST(req: NextRequest) { | ||
try { | ||
if(req.cookies.get(tokenStorageKey)) return NextResponse.json({ status: 403 }); | ||
|
||
const { password } = await req.json() as AuthRequestData; | ||
|
||
if(!password) return NextResponse.json({ status: 400 }); | ||
const md5Password = md5(password); | ||
|
||
if(md5Password !== process.env["PASSWORD"]) return NextResponse.json({ status: 401 }); | ||
const token = generateToken(md5Password); | ||
|
||
return NextResponse.json({ status: 200, token }); | ||
} catch (err) { | ||
console.log("[Server: /api/auth/login] "+ err); | ||
|
||
return NextResponse.json({ status: 500 }); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,15 @@ | ||
import { cookies } from "next/headers"; | ||
import { redirect } from "next/navigation"; | ||
|
||
import { tokenStorageKey } from "@/lib/global"; | ||
import { validateToken } from "@/lib/token"; | ||
|
||
export default function Page() { | ||
return <>{/** @todo */}</>; | ||
const cookieStore = cookies(); | ||
const token = cookieStore.get(tokenStorageKey); | ||
|
||
if(!token || !validateToken(token.value)) redirect("/login"); | ||
|
||
// default redirection | ||
redirect("/x/root"); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
/* eslint-disable react/display-name */ | ||
"use client"; | ||
|
||
import React, { forwardRef, useState } from "react"; | ||
import { Eye, EyeOff } from "lucide-react"; | ||
import { Input, InputProps } from "@nextui-org/input"; | ||
|
||
const PasswordInput = forwardRef<HTMLInputElement, InputProps>((props, ref) => { | ||
const [passwordVisible, setPasswordVisible] = useState<boolean>(false); | ||
|
||
return ( | ||
<Input | ||
endContent={ | ||
<button className="outline-none" type="button" onClick={() => setPasswordVisible((current) => !current)}> | ||
{ | ||
passwordVisible | ||
? <EyeOff className="pointer-events-none"/> | ||
: <Eye className="pointer-events-none"/> | ||
} | ||
</button> | ||
} | ||
type={passwordVisible ? "text" : "password"} | ||
autoComplete="password" | ||
ref={ref} | ||
{...props}/> | ||
); | ||
}) | ||
|
||
export default PasswordInput; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
"use client"; | ||
|
||
import React, { useState, useEffect } from "react"; | ||
import { useTheme } from "next-themes"; | ||
import { Switch } from "@nextui-org/switch"; | ||
import { Sun, Moon } from "lucide-react"; | ||
|
||
interface ThemeSwitchProps { | ||
size?: "sm" | "md" | "lg" | ||
} | ||
|
||
const ThemeSwitch: React.FC<ThemeSwitchProps> = ({ size }) => { | ||
const { setTheme, theme } = useTheme(); | ||
const [mouted, setMouted] = useState<boolean>(false); | ||
|
||
const handleSwitchTheme = (value: boolean) => { | ||
value | ||
? setTheme("light") | ||
: setTheme("dark"); | ||
}; | ||
|
||
useEffect(() => { | ||
setMouted(true); | ||
}, []); | ||
|
||
return mouted && <Switch | ||
size={size ?? "md"} | ||
startContent={<Sun size={13}/>} | ||
endContent={<Moon size={13}/>} | ||
defaultSelected={theme === "light"} | ||
onValueChange={(value) => handleSwitchTheme(value)}/>; | ||
} | ||
|
||
export default ThemeSwitch; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import { useEffect } from "react"; | ||
import { useRouter } from "next/navigation"; | ||
import Cookies from "js-cookie"; | ||
|
||
import { tokenStorageKey } from "@/lib/global"; | ||
|
||
export function useDetectCookie() { | ||
const router = useRouter(); | ||
|
||
useEffect(() => { | ||
if(!Cookies.get(tokenStorageKey)) router.push("/"); | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export const version = "0.0.1"; | ||
export const tokenStorageKey = "ferrum-token"; |
Oops, something went wrong.