From c84e223ca584c5743a176568ab0dae3aeec85789 Mon Sep 17 00:00:00 2001 From: sijinhui Date: Fri, 22 Mar 2024 14:49:10 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B5=8B=E8=AF=95=E5=A2=9E=E5=8A=A0=E9=82=AE?= =?UTF-8?q?=E4=BB=B6=E8=AE=A4=E8=AF=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/app/(admin)/admin/ana/page.tsx | 3 +- app/app/(auth)/layout.tsx | 3 +- app/app/(auth)/login/user-login-button.tsx | 57 ++++++++++++++++++---- app/page.tsx | 3 +- lib/auth.ts | 16 +++++- lib/utils.ts | 13 ++++- middleware.ts | 26 +++++----- package.json | 3 ++ prisma/schema.prisma | 1 + 9 files changed, 95 insertions(+), 30 deletions(-) diff --git a/app/app/(admin)/admin/ana/page.tsx b/app/app/(admin)/admin/ana/page.tsx index 440b90d21..1d5835598 100644 --- a/app/app/(admin)/admin/ana/page.tsx +++ b/app/app/(admin)/admin/ana/page.tsx @@ -7,7 +7,8 @@ import { Flex } from "antd"; export default async function AdminPage() { const session = await getSession(); - if (!(session?.user?.name && ADMIN_LIST.includes(session.user.name))) { + const name = session?.user?.email || session?.user?.name; + if (!(name && ADMIN_LIST.includes(name))) { // Replace '/dashboard' with the desired redirect path redirect("/"); } diff --git a/app/app/(auth)/layout.tsx b/app/app/(auth)/layout.tsx index f24f97ae0..a964db852 100644 --- a/app/app/(auth)/layout.tsx +++ b/app/app/(auth)/layout.tsx @@ -16,7 +16,8 @@ export default async function AuthLayout({ }) { const session = await getSession(); // If the user is already authenticated, redirect them to home - if (session?.user?.name && isName(session.user.name)) { + const name = session?.user?.email || session?.user?.name; + if (name && isName(name)) { // Replace '/dashboard' with the desired redirect path redirect("/"); } diff --git a/app/app/(auth)/login/user-login-button.tsx b/app/app/(auth)/login/user-login-button.tsx index 8dfa51718..7aa5853c4 100644 --- a/app/app/(auth)/login/user-login-button.tsx +++ b/app/app/(auth)/login/user-login-button.tsx @@ -1,13 +1,14 @@ "use client"; import { signIn } from "next-auth/react"; -import React, { useState, useEffect, useRef } from "react"; +import React, { useState, useEffect, useRef, use } from "react"; import { isName } from "@/lib/auth_list"; export default function UserLoginButton() { const [loading, setLoading] = useState(false); const nameInput = useRef(null); + const emailInput = useRef(null); const [username, setUsername] = useState(""); const [error, setError] = useState(false); @@ -27,18 +28,31 @@ export default function UserLoginButton() { setLoading(true); e.preventDefault(); - console.log("current,username2", username); - const result = await signIn("credentials", { - username: username, - redirect: false, - }); + let result: { error: any; url: string | null } | undefined = { + error: null, + url: null, + }; + if (emailInput.current && emailInput.current.value) { + result = await signIn("email", { + email: emailInput.current.value, + redirect: false, + }); + } else { + result = await signIn("credentials", { + username: username, + redirect: false, + }); + } setLoading(false); - if (!result?.error) { - window.location.href = "/"; - } else setError(true); + console.log("------1", result); + // if (!result?.error) { + // console.log('------2',result) + // window.location.href = result?.url || "/"; + // } else setError(true); }; useEffect(() => { + if (!username) return; if (nameInput.current) { if (!isName(username)) { setError(true); @@ -81,7 +95,7 @@ export default function UserLoginButton() { onCompositionStart={(e) => e.preventDefault()} onCompositionEnd={handleComposition} onChange={onNameChange} - required + // required placeholder="输入姓名、拼音或邮箱" className={`${ loading @@ -95,6 +109,29 @@ export default function UserLoginButton() { } `} /> + e.preventDefault()} + // onCompositionEnd={handleComposition} + // onChange={onNameChange} + // required + placeholder="邮箱验证,测试阶段" + className={`${ + loading + ? "cursor-not-allowed bg-stone-50 dark:bg-stone-800" + : "bg-white hover:bg-stone-50 active:bg-stone-100 dark:bg-black dark:hover:border-white dark:hover:bg-black" + } group my-2 flex h-10 w-full items-center justify-center space-x-2 rounded-md border border-stone-200 transition-colors duration-75 focus:outline-none dark:border-stone-700 + ${ + error + ? "focus:invalid:border-red-500 focus:invalid:ring-red-500" + : "" + } + `} + /> {/*{error &&

{error}

}*/} diff --git a/app/page.tsx b/app/page.tsx index 134a8f75e..77e3aa2e1 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -12,7 +12,8 @@ const serverConfig = getServerSideConfig(); export default async function App() { const session = await getSession(); - if (!session || !(session?.user?.name && isName(session.user.name))) { + const name = session?.user?.email || session?.user?.name; + if (!(name && isName(name))) { redirect("/login"); } diff --git a/lib/auth.ts b/lib/auth.ts index 676631337..fbae70904 100644 --- a/lib/auth.ts +++ b/lib/auth.ts @@ -1,5 +1,6 @@ import { getServerSession, type NextAuthOptions } from "next-auth"; import GitHubProvider from "next-auth/providers/github"; +import EmailProvider from "next-auth/providers/email"; import CredentialsProvider from "next-auth/providers/credentials"; import { PrismaAdapter } from "@next-auth/prisma-adapter"; import prisma from "@/lib/prisma"; @@ -27,6 +28,17 @@ export const authOptions: NextAuthOptions = { }; }, }), + EmailProvider({ + server: { + host: process.env.EMAIL_SERVER_HOST, + port: process.env.EMAIL_SERVER_PORT, + auth: { + user: process.env.EMAIL_SERVER_USER, + pass: process.env.EMAIL_SERVER_PASSWORD, + }, + }, + from: process.env.EMAIL_FROM, + }), CredentialsProvider({ // The name to display on the sign in form (e.g. "Sign in with...") name: "Credentials", @@ -66,7 +78,7 @@ export const authOptions: NextAuthOptions = { ], pages: { signIn: `/login`, - verifyRequest: `/login`, + // verifyRequest: `/login`, error: "/login", // Error code passed in query string as ?error= }, adapter: PrismaAdapter(prisma), @@ -99,7 +111,7 @@ export const authOptions: NextAuthOptions = { session.user = { ...session.user, // @ts-expect-error - id: token.sub, + id: token?.sub, // @ts-expect-error username: token?.user?.username || token?.user?.gh_username, }; diff --git a/lib/utils.ts b/lib/utils.ts index c2c0e3fad..bebabd46c 100644 --- a/lib/utils.ts +++ b/lib/utils.ts @@ -1,4 +1,4 @@ - +import bcrypt from "bcryptjs"; import {get_encoding} from "tiktoken"; @@ -18,7 +18,6 @@ export async function fetcher( } export const capitalize = (s: string) => { - if (typeof s !== "string") return ""; return s.charAt(0).toUpperCase() + s.slice(1); }; @@ -61,3 +60,13 @@ export const toDateString = (date: Date) => { export const random = (min: number, max: number) => { return Math.floor(Math.random() * (max - min + 1) + min); }; + +// 将明文处理为 hash +export function hashPassword(password: string) { + return bcrypt.hashSync(password, 10); +} + +// 对比明文和 hash 是否一致 +export function comparePassword(password: string, hashPassword: string) { + return bcrypt.compareSync(password, hashPassword); +} diff --git a/middleware.ts b/middleware.ts index f26af4795..1db069faf 100644 --- a/middleware.ts +++ b/middleware.ts @@ -18,19 +18,19 @@ export default async function middleware(req: NextRequest) { // console.log('==============,认证,', path, session) // 认证有点多此一举,页面中的认证应该已经够了 - if (!session && path !== "/login") { - // 给关键请求特殊待遇 - if (path.startsWith('/api/openai/')) { - return NextResponse.json(false, { - status: 401, - }); - } - return NextResponse.redirect(new URL("/login", req.url)); - } else if (session) { - // console.log('referer=====', DENY_LIST.includes(session?.name ?? "")) - if (isName(session?.name ?? "") && path.startsWith("/login")) - return NextResponse.redirect(new URL("/", req.url)); - } + // if (!session && path !== "/login") { + // // 给关键请求特殊待遇 + // if (path.startsWith('/api/openai/')) { + // return NextResponse.json(false, { + // status: 401, + // }); + // } + // return NextResponse.redirect(new URL("/login", req.url)); + // } else if (session) { + // // console.log('referer=====', DENY_LIST.includes(session?.name ?? "")) + // if (isName(session?.name ?? "") && path.startsWith("/login")) + // return NextResponse.redirect(new URL("/", req.url)); + // } if (path == '/login') { return NextResponse.rewrite( diff --git a/package.json b/package.json index 4eff7a577..4c97b71b8 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "@vercel/analytics": "^1.1.2", "@vercel/speed-insights": "^1.0.9", "antd": "^5.15.1", + "bcryptjs": "^2.4.3", "echarts": "^5.4.3", "emoji-picker-react": "^4.7.10", "fuse.js": "^7.0.0", @@ -35,6 +36,7 @@ "next": "^14.1.0", "next-auth": "^4.24.5", "node-fetch": "^3.3.1", + "nodemailer": "^6.9.13", "react": "^18.2.0", "react-dom": "^18.2.0", "react-markdown": "^9.0.1", @@ -53,6 +55,7 @@ }, "devDependencies": { "@tauri-apps/cli": "^1.5.8", + "@types/bcryptjs": "^2.4.6", "@types/cookie": "^0.6.0", "@types/node": "^20.11.10", "@types/react": "^18.2.48", diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 32a0eda2c..022d20013 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -21,6 +21,7 @@ model User { email String? @unique emailVerified DateTime? image String? + password String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt accounts Account[]