增加谷歌登录

This commit is contained in:
sijinhui 2024-10-02 23:43:30 +08:00
parent 47c72bf010
commit d86d5a1951
7 changed files with 123 additions and 33 deletions

View File

@ -9,7 +9,7 @@ export default function LoginByGithub() {
return (
<div
className={`group my-2 flex h-10 w-7/12 items-center justify-center space-x-2 rounded-md border border-stone-200 transition-colors duration-75 focus:outline-none dark:border-stone-700 `} //
className={`group my-2 flex h-10 w-1/12 items-center justify-center space-x-2 rounded-md border border-stone-200 transition-colors duration-75 focus:outline-none dark:border-stone-700 `} //
>
<button
disabled={loading}
@ -18,7 +18,7 @@ export default function LoginByGithub() {
e.preventDefault();
signIn("github");
}}
className={`bg-transparent hover:bg-transparent mr-40`}
className={`bg-transparent hover:bg-transparent`}
>
{loading ? (
<LoadingDots color="#A8A29E" />

View File

@ -0,0 +1,52 @@
"use client";
import LoadingDots from "@/app/components/icons/loading-dots";
import { signIn } from "next-auth/react";
import { useState } from "react";
import { GoogleCircleFilled } from "@ant-design/icons";
export default function LoginByGoogle() {
const [loading, setLoading] = useState(false);
return (
<div
className={`group my-2 flex h-10 w-1/12 items-center justify-center space-x-2 rounded-md border border-stone-200 transition-colors duration-75 focus:outline-none dark:border-stone-700 `} //
>
<button
disabled={loading}
onClick={(e) => {
setLoading(true);
e.preventDefault();
signIn("google", { redirect: false }).then((r) => {
console.log("[auth log]", r);
});
}}
className={`bg-transparent hover:bg-transparent`}
>
{loading ? (
<LoadingDots color="#A8A29E" />
) : (
<>
{/*<svg*/}
{/* className="h-6 w-6 text-gray-500 dark:text-white"*/}
{/* aria-hidden="true"*/}
{/* fill="currentColor"*/}
{/* viewBox="0 0 24 24"*/}
{/*>*/}
{/* */}
{/*</svg>*/}
<GoogleCircleFilled
style={{
fontSize: "24px",
color: "rgb(107 114 128/var(--tw-text-opacity)) !import",
}}
/>
{/*<p className="text-sm font-medium text-stone-600 dark:text-stone-400">*/}
{/* Login with GitHub*/}
{/*</p>*/}
</>
)}
</button>
<div className={`w-1`}></div>
</div>
);
}

View File

@ -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() {
{" "}
</span>
<LoginByGithub />
<LoginByGoogle />
<div className="w-5/12" />
</div>
</>
);

View File

@ -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: (
<span>
使
<br />
<span style={{ color: "red" }}></span>
</span>
),
});
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 =

View File

@ -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;
}
},

View File

@ -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))
}

View File

@ -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?