diff --git a/package.json b/package.json index 8718a0d..4340126 100644 --- a/package.json +++ b/package.json @@ -9,15 +9,16 @@ "lint": "next lint" }, "dependencies": { + "@auth/prisma-adapter": "^1.0.11", "@emotion/react": "^11.11.1", "@emotion/styled": "^11.11.0", "@fontsource/roboto": "^5.0.8", "@mui/icons-material": "^5.14.18", "@mui/lab": "^5.0.0-alpha.155", "@mui/material": "^5.14.18", - "bcryptjs": "^2.4.3", "@mui/x-date-pickers": "^6.18.3", "@prisma/client": "^5.6.0", + "bcryptjs": "^2.4.3", "dayjs": "^1.11.10", "fabric": "^5.3.0", "material-ui-popup-state": "^5.0.10", diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 49157e7..3856349 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -10,12 +10,42 @@ datasource db { url = env("DATABASE_URL") } +model Account { + id String @id @map("_id") @db.ObjectId @default(auto()) + userId String @db.ObjectId + providerType String + providerId String + providerAccountId String + refreshToken String? + accessToken String? + accessTokenExpires DateTime? + createdAt DateTime? @default(now()) + updatedAt DateTime? @updatedAt + user User @relation(fields: [userId], references: [id]) + @@unique([providerId, providerAccountId]) +} + +model Session { + id String @id @map("_id") @db.ObjectId @default(auto()) + userId String @db.ObjectId + expires DateTime + sessionToken String @unique + accessToken String @unique + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + user User @relation(fields: [userId], references: [id]) +} + model User { id String @id @default(auto()) @map("_id") @db.ObjectId email String @unique password String nickname String todos Todo[] + createdAt DateTime? @default(now()) + updatedAt DateTime? @updatedAt + accounts Account[] + sessions Session[] } model Todo { diff --git a/src/AuthSession.jsx b/src/AuthSession.jsx new file mode 100644 index 0000000..0b24df4 --- /dev/null +++ b/src/AuthSession.jsx @@ -0,0 +1,10 @@ +/* eslint-disable react/prop-types */ + +'use client'; + +import React from 'react'; +import { SessionProvider } from 'next-auth/react'; + +export default function AuthSession({ children }) { + return {children}; +} diff --git a/src/app/api/auth/[...nextauth].js b/src/app/api/auth/[...nextauth].js deleted file mode 100644 index 244d81e..0000000 --- a/src/app/api/auth/[...nextauth].js +++ /dev/null @@ -1,39 +0,0 @@ -import NextAuth from 'next-auth'; -import CredentialsProvider from 'next-auth/providers/credentials'; - -export default NextAuth({ - providers: [ - CredentialsProvider({ - // The name to display on the sign in form (e.g. "Sign in with...") - name: 'Credentials', - // The credentials is used to generate a suitable form on the sign in page. - // You can specify whatever fields you are expecting to be submitted. - // e.g. domain, username, password, 2FA token, etc. - // You can pass any HTML attribute to the tag through the object. - credentials: { - username: { - label: 'Email', - type: 'email', - placeholder: 'fitapat@example.com', - }, - password: { label: 'Password', type: 'password' }, - }, - - async authorize(credentials, req) { - // Add logic here to look up the user from the credentials supplied - const user = { id: 1, name: 'J Smith', email: 'jsmith@example.com' }; - - if (user) { - // Any object returned will be saved in `user` property of the JWT - return user; - } else { - // If you return null or false then the credentials will be rejected - return null; - // You can also Reject this callback with an Error or with a URL: - // throw new Error("error message") // Redirect to error page - // throw "/path/to/redirect" // Redirect to a URL - } - }, - }), - ], -}); diff --git a/src/app/api/auth/[...nextauth]/route.js b/src/app/api/auth/[...nextauth]/route.js new file mode 100644 index 0000000..8de1b5d --- /dev/null +++ b/src/app/api/auth/[...nextauth]/route.js @@ -0,0 +1,82 @@ +/* eslint-disable no-console */ + +import bcrypt from 'bcryptjs'; +import NextAuth from 'next-auth'; +import CredentialsProvider from 'next-auth/providers/credentials'; +import { PrismaAdapter } from '@auth/prisma-adapter'; +import { PrismaClient } from '@prisma/client'; + +const prisma = new PrismaClient(); + +const handler = NextAuth({ + adapter: PrismaAdapter(prisma), + providers: [ + CredentialsProvider({ + name: 'Credentials', + credentials: { + email: { + label: 'Email', + type: 'text', + placeholder: '이메일 주소 입력', + }, + password: { + label: 'Password', + type: 'password', + placeholder: '비밀번호 입력', + }, + }, + // 승인 + async authorize(credentials) { + if (!credentials?.email || !credentials?.password) { + return null; + } + // Prisma를 사용하여 유저 정보를 가져옴 + const user = await prisma.user.findUnique({ + where: { email: credentials.email }, + }); + + console.log(user); + + if (!user) { + return null; + } + const isCorrectPassword = await bcrypt.compare( + credentials.password, + user.password, + ); + + if (!isCorrectPassword) { + return null; + } + console.log('로그인 완료'); + return user; + }, + }), + ], + session: { + strategy: 'jwt', + }, + callbacks: { + async jwt({ token, user, session }) { + if (user) { + return { + ...token, + id: user.id, + }; + } + return token; + }, + async session({ session, token, user }) { + return { + ...session, + user: { + ...session.user, + id: token.id, + }, + }; + }, + }, + secret: process.env.NEXTAUTH_SECRET, +}); + +export { handler as GET, handler as POST }; diff --git a/src/app/layout.jsx b/src/app/layout.jsx index d589001..214f27a 100644 --- a/src/app/layout.jsx +++ b/src/app/layout.jsx @@ -5,6 +5,7 @@ import './globals.css'; import { Container } from '@mui/material'; import Header from '../components/header'; import Footer from '../components/footer'; +import AuthSession from '../AuthSession'; const inter = Inter({ subsets: ['latin'] }); @@ -18,8 +19,8 @@ export default function RootLayout({ children }) {
- - {children} + + {children}