تعلم كيفية استخدام Next-Auth بخطوات بسيطة
سنتعلم معاً في هذا الدرس كيفة عمل صلاحيات تسجيل دخول بكل سهولة بإستخدام Next.js
السلام عليكم ورحمة الله وبركاته
سنتعلم في هذا الدرس كيفية عمل (authentication) صلاحيات تسجيل دخول المستخدم باستخدام Next.js
سنقوم بإستخدام حزمة Next-Auth والتي بدورها ستسمح لنا عمل كل الصلاحيات بخطوات سهلة وبسيطة
سنقوم باستخدام تسجيل الدخول باستخدام المعرف وكلمة المرور وايضاً باستخدام جوجل
النتيجة النهائية للدرس :
الكود على Github (اضغط هنا)
متطلبات الدرس :
- المعرفة بأساسيات React.js & Next.js
ملاحظات :
لن نقوم بشرح اساسيات جافاسكريبت و React.js & Next.js وغيرها من الأساسيات مثل شرح سطر الأومر وكيفية عمل الحزم وتثبيتها ...الخ حيث يتوجب عليك معرفة هذه الأمور قبل البدء في الدرس
والآن دعونا نبدأ الدرس :
أولاً سنبدأ بتثبيت Next.js من خلال سطر الأوامر اكتب :
npx create-next-app@latest
وهذا الأمر سيقوم بتنزيل اخر نسخة من Next.js
النسخة التي تعمل لدي حالياً هي: 14.1.0
في حال اردت بتثبيت نسخة محددة قم بالتالي:
npx create-next-app@14.1.0
للمزيد من المعلومات بأمكانك الأطلاع على الرابط التالي :
https://nextjs.org/docs/getting-started/installation
الآن بعد كتابة الآمر سيقوم بسؤالك عدة اسئلة سنقوم بالأختيار كما يلي :
- Project name : سيكون next-auth (بأمكانك اختيار اي اسم تريد)
- TypeScript? No
- Eslint? Yes
- Tailwind CSS? Yes
- `src/` directory? No
- App Router? Yes
- customize the default import alias? No
الآن سيقوم بتثبيت مشروع Next.js سننتظر حتى يقوم من الإنتهاء
* كما تلاحظ قمنا باستخدام Tailwind CSS وهو اطار عمل بسيط يسمح لنا بتنسيق تطبيقنا عن طريق اضافة الكلاسات css فقط، إن لم تكن استخدمتها من قبل فلا داعي للقلق سأعطيك ملف CSS ققط قم بنسخها ولصقها كما هي
بعد الأنتهاء من تثبيت Next.js سنقوم بتنزيل حزمة اضافية وهي حزمة Next-Auth باستخدام سطر الأوامر :
npm install next-auth
قم بتشغيل المشروع عن طريق :
npm run dev
الآن سنفتح المشروع عن طريق محرر الأكواد الخاص بك وقم بأنشاء الملف التالي :
api/auth/[...nextauth]/route.js
لا بد من انشاء هذا الملف كما قمت بكتابته وإلا لن تعمل معك حزمة Next-auth
بأمكانك الأطلاع على المزيد من المعلومات من خلال الرابط التالي :
في البداية سنقوم بتسجيل الدخول بأستخدام كل من المعرف و كلمة المرور
ولعمل ذلك قم بالذهاب إلى الملف route.js وقم بإضافة الكود التالي:
import NextAuth from "next-auth" import CredentialsProvider from "next-auth/providers/credentials" export const authOptions = { providers: [ CredentialsProvider({ name: "Credentials", credentials: { identifire: { label: "Identifire", type: "text", placeholder: "Your username or email" }, password: { label: "Password", type: "password" } }, async authorize(credentials, req) { console.log('credentials: ', credentials) const profilePicture = "https://gravatar.com/avatar/205e460b479e2e5b48aec07710c08d50?size=100" const user = { id: "1", name: credentials.identifire, image: profilePicture } if (user) { return user } else { return null } } }) ], } const handler = NextAuth(authOptions) export { handler as GET, handler as POST }
كما نلاحظ هنا في البداية قمنا باستيراد NextAuth من حزمة next-auth
وبعدها ايضاً ومن نفس الحزمة قمنا باستيراد CredentialsProvider وهذا هو المزود الذي سيسمح بتسجيل الدخول باستخدام كل من المعرف وكلمة المرور وهناك العديد من المزودات والتي يرمز لها بالـ provider مثل Google - Github - Twitter - Facebook ... etc
للمزيد من المعلومات عنها قم بزيارة الرابط التالي :
بعد ذلك لدينا authOptions وهو عبارة عن اوبجيكت باضافة الـ providers والتحكم بها
في البداية بداخل هذا الاوبجيكت لدينا providers وهو عبارة عن مصفوفة سنقوم بدخلها بتعريف جميع الـ providers التي ستحتاجها في مشروعك سواء كان جوجل أو github او credentials
والآن لنستطيع تسجيل الدخول باستخدام المعرف وكلمة المروف سنحتاج لاضافة CredentialsProvider بداخل مصفوفتنا
بداخل CredentialsProvider سنقوم ايضاً باضافة عدة خيارات :
1- name: وهو الاسم
2- credentials : وهنا حيث سنعرف الحقول الازمة التي سيقوم المستخدم بملئها من اجل تسجيل الدخول، وفي حالتنا نريد المعرف وكلمة المرور ولذلك كما تلاحظ قمنا بأضافة كل من identifire & password
ان اردت بأمكانك تغيير identifire بـ username أو email على سبيل المثال ولكن في هذا الدرس قررت جعلها identifire بمعنى المعرف أي يستطيع المستخدم الدخول باستخدام اسم المستخدم أو البريد الإلكتروني، وطبعاً ذلك قد يختلف حسب حاجة التطبيق الذي تعمل عليه والخيارات التي تريد توفيرها في تطبيقك
الآن بعد ذلك لدينا كل من label - type - placeholder وطبعاً من تسمياتها تستطيع ان تستنتج بأنها خيارات الحقول التي سيملئها المستخدم عند عملية تسجيل الدخول، تستطيع التغيير فيها ايضاً بحسب ما تراه مناسباً لك ولمشروعك
الآن من خلال المتصفح اذهب الى الرابط التالي:
النتيجة :
كما ترى قام next-auth بعمل كل شيء من صفحة الدخول إلى وحقول وزر الإدخال بشكل تلقائي
وقبل أن نقوم بالتجربة دعنا نقوم بشرح بقية الكود اعلاه
حالياً كل ما تبقى لدينا هو الدالة authorize وهنا حيث سيقوم next-auth بتولي عملية تسجيل الدخول بعد الضغط على زر تسجيل الدخول
طبعاً في العادة هنا حيث سنقوم بمقارنة البيانات المرسلة بما لديك في قاعدة البيانات ومن ثم ستقوم بجلب بيانات المستخدم من قاعدة البيانات وارسالها
ولكن نحن هنا لن نقوم باستخدام هذه الخطوة حيث سنقوم فقط بأخذ المعلومات المدخلة من قبل المستخدم وتسجيل الدخول بشكل تلقائي بما أننا نقوم هنا فقط بشرح وتوضيح كيفة عمل next-auth وربما سيكون اختبار جيد بالنسبة لك أن تقوم بإدراج قاعدة بيانات والعمل بها
حسنا كما موضح لنا في الكود اعلاه أن الدالة authorize تأخذ المعامل credentials وهذا المعامل يقوم بحمل البيانات التي ادخلها المستخدم
بمعنى تستطيع الوصول للمعرف عن طريق credentials.identifire ان كنت استخدمت username أو email ستقوم بالوصل اليه عن طريق identifire.username أو identifire.email
الآن بعد ذلك سأقوم بعمل المتغير user وقمنا باضافة معلومات المستخدم بداخلها (يفترض أن تكون بيانات المستخدم من قاعدة البيانات)
طبعاً كما ترى قمت بإضافة profilePicture وهي فقط صورة افتراضية قمت بإضافتها للمستخدم تستطيع تغييرها بأي صورة اخرى إن اردت
حسنا الآن لدينا كل ما يلزم لتسجيل الدخول واظهار معلومات المستخدم داخل تطبيقنا حيث ستستطيع الوصل إلى معلومات المستخدم من خلال next-auth hook (useSession())
ولنفعل ذلك الآن دعنا نتجه الى ملف app/page.js حيث سنقوم بتجربة ذلك ...
ولكن قبل ذلك سنحتاج لفعل خطوة اخرى وهي أن نقوم بتغليف تطبيقننا بـ <SessionProvider> حتى نستطيع الوصل إلى useSession
ولعمل ذلك سنقوم بإنشاء ملف providers/AuthProvider.js في المسار الرئيسي للتطبيق وقم بإضافة الكود التالي:
"use client" import { SessionProvider } from "next-auth/react"; const AuthProvider = ({children}) => { return ({children} ) } export default AuthProvider
يجب اضافة "use client" اعلى الصفحة وإلا ستتحصل على خطأ
الآن سنذهب إلى ملف app/layout.js وسنقوم بتغليف تطبيقنا بـ AuthProvider حتى نستطيع استخدام useSession() من أي مكان في التطبيق
حيث سيكون ملف layout.js كما في التالي :
import { Inter } from "next/font/google"; import "./globals.css"; import AuthProvider from "@/providers/AuthProvider"; import Link from "next/link"; const inter = Inter({ subsets: ["latin"] }); export const metadata = { title: "Auth Next App", description: "Generated by create next app", }; export default function RootLayout({ children, }) { return ( <html lang="en"> <body className={inter.className}> <AuthProvider> <Link href="/" className="text-lg">Home</Link> <main className="main"> <h1 className="text-2xl mb-10">Next Auth</h1> {children} </main> </AuthProvider> </body> </html> ); }
هنا قمت بأضفة العنصر main فقط كخطوة تنسيقية لا اكثر
الآن كخطوة اخرى من اجل تنسيق التطبيق اريد منك الذهاب إلى ملف app/globals.css وتقوم باستبدال محتوياته بالكود التالي :
@tailwind base; @tailwind components; @tailwind utilities; @layer components { :root { @apply p-10 h-[100vh] overflow-hidden flex flex-col justify-center text-zinc-800 bg-[#ececec]; } .main { @apply h-[400px] bg-white p-5 flex flex-col items-center justify-center mt-2 rounded-[2rem]; } .btn { @apply drop-shadow px-10 py-3 rounded-lg; } .btn-primary { @apply bg-white hover:bg-gray-200 text-black; } .google { @apply text-2xl font-bold text-rose-600; } .avatar { @apply rounded-full drop-shadow-lg my-5; } }
الآن سنعود لنكمل العمل على ما تبقى من next-auth حتى نستطيع اظهار بيانات المستخدم ...
اذهب الآن إلى ملف app/page.js وقم بحذف جميع محتويات الملف واضف الكود التالي:
'use client' import Image from "next/image" import { signIn, signOut, useSession } from "next-auth/react" import Link from "next/link" export default function Home() { const { data: session, status } = useSession() console.log(session) return ( <div> {session ? <div className="flex flex-col items-center "> <p className="">welcome {session.user?.name}</p> <Image priority={true} // Change this line src={session?.user?.image} alt="image" width={100} height={100} className="avatar" /> <button className="btn btn-primary" onClick={() => signOut()}> Signout </button> </div> : <div className="flex flex-col items-center"> <Link href='/api/auth/signin' className="btn btn-primary mb-5" > Sign in </Link> <button onClick={() => signIn('google')} className="btn btn-primary" > <span className="google">G </span>Sign in with google </button> </div> } </div> ) }
الآن ان توجهت للصفحة الرئيسة ستحصل على الخطأ Invalid src prop
هذه احدى الأخطاء التي قد تظهر عند استخدام next/image حيث يتوجب عليك تعريف المضيف في ملف next.config
لمزيد من المعلومات زر الرابط التالي :
ولحل هذه المشكلة سنتجه لملف next.config.mjs
const nextConfig = { images: { domains: [ "lh3.googleusercontent.com", "gravatar.com" ], } };
لقد قمت ايضاً بإضافة lh3.googlegoogleusercontent.com لاننا سنحتاجه فيما بعد عندما نقوم بعمل تسجيل الدخول باستخدام جوجل لعرض صورة الملف الشخصي
الآن دعنا نعود لملف app/page.js ان القيت نظرة على الكود فلا اعتقد بأنك ستواجه مشكلة في فهم الكود، ولكن ما يهمنا هنا هو useSession() وهذا هو الهوك الذي يقدمه لنا Next.js من اجل التحقق والوصول الى بيانات المستخدم ومعرفة ما إذا كان المستخدم قيد تسجيل الدخول أم لا
كما ترى ايضا قمنا باستخدام const { data: session, status } = useSession()
الآن نستطيع بكل بساطة أن نصل إلى بيانات المستخدم في حال كان قيد تسجيل الدخل باستخدام session?.user او حتى معرفة حالة المستخدم إن كان قيد تسجيل الدخول ام لا باستخدام status جرب طباعة المتغيير في الكونسول لرؤية النتيجة
ملاحظة: في حال لم يكن هناك مستخدم فقيمة session ستكون null و status ستكون unauthenticated
ايضاً كما تشاهد قمت بإضافة زر تسجيل الدخول عن طريق جوجل لنتجاهله حالياً وسنعود اليه لاحقاً
يهمنا ايضاً زر تسجيل الخروج حيث توفر لنا next-auth الدالة signOut لتسجيل الخروج بكل سهولة سنقوم بتجربتها بعد ان نقوم بتسجيل الدخول
الآن قم بالضغط على رز Sign in وقم بعمل بتجربة عملية تسجيل الدخول وبعدها توجه للصفحة الرئيسية
النتيجة :
الآن كما تشاهد مبروك لقد قمت بعملية تسجيل الدخول بشكل سليم وبطريقة سهلة وسريعة جداً بفضل next-auth
دعنا نقوم الآن بتسجيل الدخول باستخدام جوجل ...
في الواقع عملية التسجيل باستخدام جوجل بـ next-auth اسهل واسرع بكثير من تسجيل الدخول باستخدام credentials
ولكن قبل ذلك هناك خطوة مزعجة نوعاً ما وهي انشاء تطبيق عن طريق جوجل والحصل على client id و secret id لذلك يجب علينا فعلها
ولعمل ذلك سنتجه لموقع cloud.google عن طريق الرابط التالي :
وقم باتباع الخطوات التالية :
1- قم بتسجيل الدخول ومن ثم من في اعلى القائمة اضغط على console
2- الآن اضغط على زر الاسقاط في اعلى الصفحة وقم باختيار New Project
3- قم بادخال البيانات الازمة ثم اضغط على create
4- ستنتظر قليلاً حتى يقوم جوجل بعمل التطبيق ثم ستعود من جديد وتضغط على زر الاسقاط وتختار التطبيق الذي قمت بإنشائه
5- الآن اذهب الى APIs & Services وبعدها في الصفحة التالية من القائمة اختر OAuth consent screen قم باختيار External ثم اضغط create
6- الآن سنقوم بملئ بيانات App information (الحقول التي عليها علامة * حمراء اجبارية) سنتجاهل بقية الحقول الغير مهمة من اجل اختصار الوقت في الشرح
* App name => ادخل اسم التطبيق
* User support email => قم بإدخال ايميلك الشخصي
* authorized domains => ADD DOMAIN
* Developer contact information => ادخل بريدك الالكتروني
* SAVE AND CONTINUE
* الآن بقية الصفحات سنقوم فقط بالضغط على SAVE AND CONTINUE فقط
7- الآن سنعود مرة اخرى الى APIs & Services وسنقوم من القائمة الجانبية باختيار Credentials ثم من اعلى الصفحة اضغط على CREATE CREDENTIALS ثم اختر OAuth client ID
الآن سنقوم ببعض الخطوات
* Application type => Web application
* Name => YOUR_APP_NAME
* Authorized JavaScript origins => ADD URI => http://localhost:3000
* Authorized redirect URIs => ADD URI => http://localhost:3000/api/auth/callback/google
*الآن قم بحفظ التغيرات
*ملاحظة هذه الخطوة مهمة جداً وإلا لن يسمح لك جوجل بالوصل الى التطبيق
8- الآن سيقوم جوجل باعطائك كل من Client ID & Client secret قم بحفظ هذه البيانات لأننا سنحتاجها من اجل عملية تسجيل الدخول
الآن دعنا نعود الى تطبيقنا على Next.js وقم بأنشاء الملف .env بداخله سنقوم بإدخال المعلومات التالية :
GOOGLE_ID=YOUR_CLIENT_GOOGLE_ID
GOOGLE_SECRET=YOUR_GOOGLE_SECRET
قم باستبدال كل من YOUR_CLIENT_GOOGLE_ID & YOUR_GOOGLE_SECRET بالقيم الخاصة بك
الآن سنعود الى ملف route.js الخاص بنا وفي اعلى الصفحة قم باستدعاء Google Provider كما في التالي :
import GoogleProvider from "next-auth/providers/google"
الآن سنقوم بتعريف ذلك بداخل authOptions كما في التالي :
export const authOptions = { providers: [ GoogleProvider({ clientId: process.env.GOOGLE_ID, clientSecret: process.env.GOOGLE_SECRET, }), ...
بعد فعل هذا مبارك عليك اصبح تطبيقك يدعم تسجيل الدخول عبر جوجل بشكل تلقائي
دعنا نذهب لصفحة تسجيل الدخول الخاصة بنا وانظر الى النتيجة...
كما ترى اصبح لدينا زر تسجيل الدخول عبر جوجل الآن لو قمت باضغط على الزر يفترض ان تتمكن من تسجيل الدخول باستخدام جوجل
الآن بنفس الطريقة يمكنك استخدم تسجيل الدخول باستخدام اي مزود آخر مثل Github - Facebook - Twitter وغيرها الكثير بأمكانك الإطلاع على الرابط التالي لمزيد من المعلومات :
الآن لنلقي نظرة على الصفحة الرئيسية بعد تسجيل الدخول باستخدام جوجل :
كما تشاهد لدينا معلومات المستخدم وصورة الملف الشخصي اذاً مبارك عليك تمكنت الدخول باستخدام جوجل بهذه السهولة
الآن لو عدت للملف app/page.js تتذكر بأننا قمنا بعمل زر للدخول باستخدام جوجل
الآن لو سجلت الخروج وجربت استخدام هذا الزر ستتمكن ايضاً من الدخول باستخدام جوجل وذلك لأن next-auth يقدم لنا الدالة signIn('google') لتسجيل الدخول بسهولة كل ما عليك تمرير اسم provider بداخل الدالة signIn كمعامل سواء كان جوجل أو فيس بوك أو غيرها من المزودات وستتمكن من تسجيل الدخول بسهولة
الآن وصلنا إلى نهاية الدرس وهذا الكود النهائي لتطبيقنا :
التطبيق على Github (اضغط هنا)
//app/layout.js import { Inter } from "next/font/google"; import "./globals.css"; import AuthProvider from "@/providers/AuthProvider"; const inter = Inter({ subsets: ["latin"] }); export const metadata = { title: "Auth Next App", description: "Generated by create next app", }; export default function RootLayout({ children, }) { return ( <html lang="en"> <body className={inter.className}> <AuthProvider> <main className="main"> <h1 className="text-2xl mb-10">Next Auth</h1> {children} </main> </AuthProvider> </body> </html> ); }
//api/auth/[...nextauth]/route.js import NextAuth from "next-auth" import GoogleProvider from "next-auth/providers/google" import CredentialsProvider from "next-auth/providers/credentials"; export const authOptions = { providers: [ GoogleProvider({ clientId: process.env.GOOGLE_ID, clientSecret: process.env.GOOGLE_SECRET, }), CredentialsProvider({ name: "Credentials", credentials: { identifire: { label:"Identifire", type: "text", placeholder: "Your username or email" }, password: { label: "Password", type: "password" } }, async authorize(credentials, req) { console.log('credentials: ', credentials) const profilePicture = "https://gravatar.com/avatar/205e460b479e2e5b48aec07710c08d50?size=100" const user = { id: "1", name: credentials.identifire, image: profilePicture } if (user) { return user } else { return null } } }) ], } const handler = NextAuth(authOptions) export { handler as GET, handler as POST }
//app/page.js 'use client' import Image from "next/image" import { signIn, signOut, useSession } from "next-auth/react" import Link from "next/link" export default function Home() { const { data: session, status } = useSession() console.log(session) return ( <div> {session ? <div className="flex flex-col items-center "> <p className="">welcome {session.user?.name}</p> <Image priority={true} // Change this line src={session?.user?.image} alt="image" width={100} height={100} className="avatar" /> <button className="btn btn-primary" onClick={() => signOut()}> Signout </button> </div> : <div className="flex flex-col items-center"> <Link href='/api/auth/signin' className="btn btn-primary mb-5" > Sign in </Link> <button onClick={() => signIn('google')} className="btn btn-primary" > <span className="google">G </span>Sign in with google </button> </div> } </div> ) }
//providers/AuthProvider.js "use client" import { SessionProvider } from "next-auth/react"; const AuthProvider = ({children}) => { return ({children} ) } export default AuthProvider
ليست هناك تعليقات