From d86d5a19517c8c133b1998b83a87259187be6281 Mon Sep 17 00:00:00 2001 From: sijinhui Date: Wed, 2 Oct 2024 23:43:30 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=B0=B7=E6=AD=8C=E7=99=BB?= =?UTF-8?q?=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/app/(auth)/login/loginByGithub.tsx | 4 +- app/app/(auth)/login/loginByGoogle.tsx | 52 ++++++++++++++++++++++++ app/app/(auth)/login/page.tsx | 3 ++ app/app/(auth)/login/user-login-core.tsx | 23 +++++++++++ lib/auth.ts | 34 +++++++++++----- middleware.ts | 4 +- prisma/schema.prisma | 36 ++++++++-------- 7 files changed, 123 insertions(+), 33 deletions(-) create mode 100644 app/app/(auth)/login/loginByGoogle.tsx diff --git a/app/app/(auth)/login/loginByGithub.tsx b/app/app/(auth)/login/loginByGithub.tsx index d9a30a853..91ea2d7f3 100644 --- a/app/app/(auth)/login/loginByGithub.tsx +++ b/app/app/(auth)/login/loginByGithub.tsx @@ -9,7 +9,7 @@ export default function LoginByGithub() { return (
+
+
+ ); +} diff --git a/app/app/(auth)/login/page.tsx b/app/app/(auth)/login/page.tsx index 86a6ef4f9..f5763c5f4 100644 --- a/app/app/(auth)/login/page.tsx +++ b/app/app/(auth)/login/page.tsx @@ -1,4 +1,5 @@ import LoginByGithub from "./loginByGithub"; +import LoginByGoogle from "./loginByGoogle"; import UserLoginCore from "./user-login-core"; export default function LoginPage() { @@ -28,6 +29,8 @@ export default function LoginPage() { 其它登录方式{" "} + +
); diff --git a/app/app/(auth)/login/user-login-core.tsx b/app/app/(auth)/login/user-login-core.tsx index 3c92b3891..f81f9ac48 100644 --- a/app/app/(auth)/login/user-login-core.tsx +++ b/app/app/(auth)/login/user-login-core.tsx @@ -14,6 +14,7 @@ import { UserOutlined, MailOutlined, LoadingOutlined } from "@ant-design/icons"; import type { FormProps } from "antd"; import { SignInOptions } from "next-auth/react"; import { getSession } from "next-auth/react"; +import { useSearchParams } from "next/navigation"; export default function UserLoginCore() { const [loading, setLoading] = useState(false); @@ -24,6 +25,27 @@ export default function UserLoginCore() { const [notification, notificationContextHolder] = notificationModule.useNotification(); + const searchParams = useSearchParams(); + const error = searchParams.get("error"); + + useEffect(() => { + switch (error) { + case "AccessDenied": + openNotification("error", { + message: "登录失败", + description: ( + + 无权限,仅提供给熟人使用 +
+ 请主动联系管理员解锁 +
+ ), + }); + break; + default: + break; + } + }); const openNotification = (level: string, arms: NotificationArgsProps) => { if (level === "error") { notification.error({ @@ -119,6 +141,7 @@ export default function UserLoginCore() { } signIn(loginProvider, signInOptions).then((result) => { setLoading(false); + console.log("[auth log]", result); if (!result?.error) { // 如果没有密码,且登录成功了,说明需要设置密码 let result_url = diff --git a/lib/auth.ts b/lib/auth.ts index 7562a60a8..f579a7783 100644 --- a/lib/auth.ts +++ b/lib/auth.ts @@ -1,7 +1,8 @@ import {getServerSession, type NextAuthOptions, Theme} 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 Github from "next-auth/providers/github"; +import Email from "next-auth/providers/email"; +import Credentials from "next-auth/providers/credentials"; +import Google from "next-auth/providers/google" import {PrismaAdapter} from "@next-auth/prisma-adapter"; import prisma from "@/lib/prisma"; import { User } from "@prisma/client"; @@ -23,7 +24,7 @@ export const authOptions: NextAuthOptions = { useSecureCookies: SECURE_COOKIES, secret: process.env.NEXTAUTH_SECRET, providers: [ - GitHubProvider({ + Github({ clientId: process.env.AUTH_GITHUB_ID as string, clientSecret: process.env.AUTH_GITHUB_SECRET as string, profile(profile) { @@ -37,9 +38,10 @@ export const authOptions: NextAuthOptions = { }, httpOptions: { timeout: 50000, - } + }, + allowDangerousEmailAccountLinking: true, }), - EmailProvider({ + Email({ server: { host: process.env.EMAIL_SERVER_HOST, port: parseInt(process.env.EMAIL_SERVER_PORT ?? "0"), @@ -83,7 +85,7 @@ export const authOptions: NextAuthOptions = { } }, }), - CredentialsProvider({ + Credentials({ // The name to display on the sign in form (e.g. "Sign in with...") name: "Credentials", // `credentials` is used to generate a form on the sign in page. @@ -110,7 +112,7 @@ export const authOptions: NextAuthOptions = { user['name'] = username; } // 目前用户不存在,则会创建新用户。 - let existingUser = await existUser(user); // await insertUser(user) + let existingUser = await existUser(user); if (!existingUser) { user['allowToLogin'] = !!await getSetting("allowNewUser"); existingUser = await insertUser(user); @@ -125,7 +127,12 @@ export const authOptions: NextAuthOptions = { // You can also Reject this callback with an Error thus the user will be sent to the error page with the error message as a query parameter } } - }) + }), + Google({ + clientId: process.env.GOOGLE_CLIENT_ID, + clientSecret: process.env.GOOGLE_CLIENT_SECRET, + allowDangerousEmailAccountLinking: true, + }), ], pages: { signIn: `/login`, @@ -180,13 +187,18 @@ export const authOptions: NextAuthOptions = { }, // 过滤不存在的用户 async signIn({ user, account, profile, email, credentials }) { - const existingUser = await existUser(user as User); + let existingUser = await existUser(user as User); + if (!existingUser) { + user['allowToLogin'] = !!await getSetting("allowNewUser"); + existingUser = await insertUser(user) + } // console.log('---', user, 'account', account, 'email', email, 'exist', existingUser) // 顺便过滤掉不允许登录的用户 - return !!existingUser && existingUser.allowToLogin; + return existingUser.allowToLogin; }, // 重定向 async redirect({ url, baseUrl }) { + console.log('---------', url, new URL(url), baseUrl) return baseUrl; } }, diff --git a/middleware.ts b/middleware.ts index 745b4314f..2f215acc3 100644 --- a/middleware.ts +++ b/middleware.ts @@ -24,11 +24,11 @@ export default async function middleware(req: NextRequest) { if (!isAdminUser) return NextResponse.json({error: '无管理员授权'}, { status: 401 }); } // 不是用户且页面不是登录页 - if (!isUser && path !== "/login" ) { + if (!isUser && !path.startsWith("/login") ) { return NextResponse.redirect(new URL("/login", req.url)); } // 如果登录了且页面是登录页面 - if (isUser && path == "/login") { + if (isUser && path.startsWith("/login")) { return NextResponse.redirect(new URL("/", req.url)) } diff --git a/prisma/schema.prisma b/prisma/schema.prisma index b63668732..19b88ad51 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -18,24 +18,24 @@ generator client { } model User { - id String @id @default(cuid()) - name String? + id String @id @default(cuid()) + name String? // if you are using Github OAuth, you can get rid of the username attribute (that is for Twitter OAuth) - username String? @unique - gh_username String? @unique - email String? @unique - emailVerified DateTime? - image String? - password String? + username String? @unique + gh_username String? @unique + email String? @unique + emailVerified DateTime? + image String? + password String? // 默认每人每天限额20k,但数据库存储0 - everyLimitToken Int? @default(0) - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - allowToLogin Boolean @default(true) - isAdmin Boolean? @default(false) - accounts Account[] - sessions Session[] - logs LogEntry[] + everyLimitToken Int? @default(0) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + allowToLogin Boolean @default(false) + isAdmin Boolean? @default(false) + accounts Account[] + sessions Session[] + logs LogEntry[] } model Account { @@ -46,11 +46,11 @@ model Account { providerAccountId String refresh_token String? refresh_token_expires_in Int? - access_token String? + access_token String? @db.VarChar(512) expires_at Int? token_type String? scope String? - id_token String? + id_token String? @db.Text session_state String? oauth_token_secret String? oauth_token String?