Procházet zdrojové kódy

add migrate ,admin page,middleware

maa3520 před 1 rokem
rodič
revize
ac5e453be5

+ 5 - 0
src/app/[lang]/(dashboard)/admin/page.jsx

@@ -0,0 +1,5 @@
+const Page = () => {
+  return <h1>Admin page!</h1>
+}
+
+export default Page

+ 30 - 16
src/app/api/login/route.js

@@ -1,17 +1,34 @@
 // Next Imports
-import { NextResponse } from 'next/server'
+import {
+  NextResponse
+} from 'next/server'
+import {
+  PrismaClient
+} from '@prisma/client';
+
+const prisma = new PrismaClient();
 
-// Mock data for demo purpose
-import { users } from './users'
 
 export async function POST(req) {
   // Vars
-  const { email, password } = await req.json()
-  const user = users.find(u => u.email === email && u.password === password)
+  const {
+    email,
+    password
+  } = await req.json()
+
+  const user = await prisma.user.findUnique({
+    where: {
+      email: email
+    },
+  });
+
   let response = null
 
   if (user) {
-    const { password: _, ...filteredUserData } = user
+    const {
+      password: _,
+      ...filteredUserData
+    } = user
 
     response = {
       ...filteredUserData
@@ -20,15 +37,12 @@ export async function POST(req) {
     return NextResponse.json(response)
   } else {
     // We return 401 status code and error message if user is not found
-    return NextResponse.json(
-      {
-        // We create object here to separate each error message for each field in case of multiple errors
-        message: ['Email or Password is invalid']
-      },
-      {
-        status: 401,
-        statusText: 'Unauthorized Access'
-      }
-    )
+    return NextResponse.json({
+      // We create object here to separate each error message for each field in case of multiple errors
+      message: ['Email or Password is invalid']
+    }, {
+      status: 401,
+      statusText: 'Unauthorized Access'
+    })
   }
 }

+ 7 - 9
src/app/api/login/users.js

@@ -1,11 +1,9 @@
 // ** Fake user data and data type
 // =============== Fake Data ============================
-export const users = [
-  {
-    id: 1,
-    name: 'John Doe',
-    password: 'admin',
-    email: 'admin@vuexy.com',
-    image: '/images/avatars/1.png'
-  }
-]
+export const users = [{
+  id: 1,
+  name: 'Steve Liu',
+  password: 'admin',
+  email: 'admin@vuexy.com',
+  image: '/images/avatars/1.png'
+}]

+ 5 - 11
src/app/api/test/route.js

@@ -1,17 +1,11 @@
 // /api/test/routes.js
 // Next Imports
-import {
-  NextResponse
-} from 'next/server'
-
-import {
-  PrismaClient
-} from '@prisma/client';
-
-const prisma = new PrismaClient();
+import { NextResponse } from 'next/server'
+import { PrismaClient } from '@prisma/client'
 
+const prisma = new PrismaClient()
 
 export async function GET() {
-  const accounts = await prisma.account.findMany();
-  return NextResponse.json(accounts)
+  const users = await prisma.user.findMany()
+  return NextResponse.json(users)
 }

+ 4 - 0
src/libs/auth.js

@@ -43,6 +43,8 @@ export const authOptions = {
           })
 
           const data = await res.json()
+          console.log("login data")
+          console.log(data)
 
           if (res.status === 401) {
             throw new Error(JSON.stringify(data))
@@ -108,6 +110,7 @@ export const authOptions = {
          * in token which then will be available in the `session()` callback
          */
         token.name = user.name
+        token.role = user.role
       }
 
       return token
@@ -116,6 +119,7 @@ export const authOptions = {
       if (session.user) {
         // ** Add custom params to user in session which are added in `jwt()` callback via `token` parameter
         session.user.name = token.name
+        session.user.role = token.role
       }
 
       return session

+ 25 - 2
src/middleware.js

@@ -15,6 +15,8 @@ import { ensurePrefix, withoutSuffix } from '@/utils/string'
 
 // Constants
 const HOME_PAGE_URL = '/dashboards/crm'
+const adminRoutes = ['/admin']; // 假設這些是需要 admin 權限的路由
+
 
 const getLocale = request => {
   // Try to get locale from URL
@@ -31,7 +33,9 @@ const getLocale = request => {
   const locales = i18n.locales
 
   // Use negotiator and intl-localematcher to get best locale
-  const languages = new Negotiator({ headers: negotiatorHeaders }).languages(locales)
+  const languages = new Negotiator({
+    headers: negotiatorHeaders
+  }).languages(locales)
   const locale = matchLocale(languages, locales, i18n.defaultLocale)
 
   return locale
@@ -64,6 +68,22 @@ export default withAuth(
 
     // If the user is logged in, `token` will be an object containing the user's details
     const token = request.nextauth.token
+    console.log('withAuth middleware token:')
+    console.log(token)
+
+    // 獲取用戶角色,假設 token 中包含了 role 資訊
+    const userRole = token?.role;
+
+    const isAdminRoute = adminRoutes.some(route => {
+      const langPrefix = locale ? `/${locale}` : '';
+      return pathname.startsWith(`${langPrefix}${route}`);
+    });
+    console.log('isAdminRoute: ' + isAdminRoute)
+    console.log('userRole: ' + userRole)
+    if (isAdminRoute && userRole !== 'admin') {
+      // 如果不是 admin 但試圖訪問 admin 路由,重定向到登入頁或主頁
+      return NextResponse.redirect(new URL('/login', request.url));
+    }
 
     // Check if the user is logged in
     const isUserLoggedIn = !!token
@@ -82,7 +102,9 @@ export default withAuth(
       let redirectUrl = '/login'
 
       if (!(pathname === '/' || pathname === `/${locale}`)) {
-        const searchParamsStr = new URLSearchParams({ redirectTo: withoutSuffix(pathname, '/') }).toString()
+        const searchParamsStr = new URLSearchParams({
+          redirectTo: withoutSuffix(pathname, '/')
+        }).toString()
 
         redirectUrl += `?${searchParamsStr}`
       }
@@ -107,6 +129,7 @@ export default withAuth(
   },
   {
     callbacks: {
+      //authorized: ({ token }) => !!token
       authorized: () => {
         // This is a work-around for handling redirect on auth pages.
         // We return true here so that the middleware function above

+ 2 - 0
src/prisma/migrations/20240430070605_jicnic_role/migration.sql

@@ -0,0 +1,2 @@
+-- AlterTable
+ALTER TABLE `user` ADD COLUMN `role` VARCHAR(191) NOT NULL DEFAULT 'user';

+ 1 - 0
src/prisma/schema.prisma

@@ -42,6 +42,7 @@ model User {
   emailVerified DateTime?
   image         String?
   password      String    @default("password")
+  role      String    @default("user")
   accounts      Account[]
   sessions      Session[]
 }

+ 18 - 4
src/prisma/seeds/seed.js

@@ -4,13 +4,27 @@ const {
 const prisma = new PrismaClient();
 
 async function main() {
-  const user = await prisma.user.create({
+  const user1 = await prisma.user.create({
     data: {
       id: 'u1',
       name: 'John Doe',
-      email: 'john.doe@example.com',
-      emailVerified: new Date(),
-      image: 'http://example.com/image.jpg'
+      email: 'admin@vuexy.com',
+      emailVerified: new Date('2024-04-29T06:19:25.161Z'),
+      image: '/images/avatars/1.png',
+      password: 'admin',
+      role: 'user'
+    },
+  });
+
+  const user2 = await prisma.user.create({
+    data: {
+      id: 'u2',
+      name: 'Steve Liu',
+      email: 'manto07m@gmail.com',
+      emailVerified: new Date('2024-04-29T06:19:25.161Z'),
+      image: '/images/avatars/2.png',
+      password: 'password',
+      role: 'admin'
     },
   });