احراز هویت (Authentication) با استفاده از NextAuth.js

سلام دوستان من دوباره اومدم با یک مقاله جدید ?? همونطور که از عنوان مقاله مشخصه توی این مقاله میخوام عملیات احراز هویت ( یا به زبان غربی Authenticate) از طریق GitLab با استفاده از NextAuth.js رو براتون توضیح بدم. توی این مقاله قصد دارم اول یه توضیح مختصری درباره اینکه NextAuth.js اصلا چی هست و چه کاربردی داره رو براتون توضیح بدم و بعد باهم کاربرد اون رو در غالب یه مینی پروژه با استفاده از Nextjs13 و Typescript باهم انجام بدیم . پس بزن بریم ?درباره NextAuth.jsقبل از اینکه NextAuth.js تعریف کنم اجازه بدید اول Auth.js تعریف کنم که یک به عنوان یک راه حل جامع و کامل احراز هویت بصورت open source برای Web application بکار برده میشه و NextAuth.js رو برای پروژه های Nextjs شما عرضه کرده. حالا این داداشمون (یعنی Auth.js) اومده برای سه تا فریمورک غول، این نعمت بزرگش رو ارائه داده?:فریمورک Next.js: یک فریمورک انعطاف پذیر React که به شما امکاناتی برای ایجاد Web application های سریع رو می ده.ابزاری که کامل باشه برای هر توسعه دهنده React که برای یادگیری و بهبود پروژه های خودش استفاده کنه ، بدون شک Next.js است. ( که من میخوام از این یکی سلطان استفاده کنم ?).فریمورک SolidStart: همونطور که میدونید Web application ها اغلب شامل اجزای بسیاری هستن از جمله Data baseها، سرورها، front-end ، bundler ، fetching/mutations ، Chaching و زیرساخت و... حالا این فریمورک میگه " دوستان خوبم به گوش باشید، من بسیاری از این موارد رو خودم handle میکنم و در نهایت اون ها رو بصورت یکپارچه با هم ادغام میکنم . بدون درد و خونریزی ?" و این هم بگم که این فریمورک بر پایه Solidjs و Solid Router هستشفریمورک SvelteKit: ایشون هم در واقع یکی دیگه از فریم ورک هایی هست که برای توسعه Web application بکار برده میشه این نکته رو در نظر داشته باشید وقتی از Svelte استفاده میکنید ، فریمورک اون باید SvelteKit باشه ، یه جور مثل این می مونه که وقتی دارید با React کار میکنید در کنارش از Nextjs استفاده میکنید یا وقتی دارید از vue استفاده کنید در کنارش از Nuxt استفاده میکنید. شروع مینی پروژهخب دوستان خوبم از هر چه بگذریم سخن مینی پروژه خوش تر است ? خب برای شروع دوستان توی مسیر مورد نظرتون که میخواید پروژه Next تون رو نصب و اجرا کنید ، بروید و دستور زیر رو توی ترمینال IDE خودتون ( که من از VScode استفاده میکنم. ) وارد کنید npx create-next-app@latestقبل از شروع نصب سوال هایی میپرسه، من ساختار پروژه رو براساس app گفتم ایجاد کنه نه src . و اینکه از Typescript هم استفاده میکنم ( نگران نباشید سلیقه ای هست و به موضوع بحثمون وابستگی نداره رفقا?).پکیج بعدی که باید نصب کنید دوستان، NextAuth.js هست. npm install next-auth ☢️توجه..توجه . دوستان من زیاد روی UI تمرکز نکردم و گذاشتم به سلیقه خودتون چون خواستم تمرکز رو بزارم برای هدف اصلی بحثمون. پس در هنگام بروز هر حادثه آرامشتون رو حفظ کنید و ماسک های اکسیژن از سقف براتون آویزون میشه و میتونین استفاده کنید?.خب دوستان خوبم وارد سایت NextAuth.js بشین و از پنل سمت چپ گزینه Providers کلیک کنید، از منوی منوی کشویی که باز میشه میتونید متوجه بشید به شما لیستی از گزینه هایی رو در اختیارتون میزاره که از طریق اون ها میتونید عملیات Authentication رو انجام بدید. خب ما میخوایم با استفاده از GitLab این عملیات رو انجام بدیم پس از داخل منوی باز شده، گزینه GitLab رو انتخاب کنید. در بخش Configuration روی لینک پایین اون کلیک کنید ( https://gitlab.com/-/profile/applications ) فقط دوستان حواستون باشه حتما باید حساب کاربری توی GitLab داشته باشید.حالا بعد از اینکه وارد صفحه مورد نظر شدین روی دکمه Add new application ( که در تصویر مشخص کردم) کلیک کنیدخب توی صفحه ای براتون باز شد در قسمت Add new application ازتون یه Name میخواد و یه Redirect URI . توی قسمت Name اسم دلخواه تون رو بنویسید ولی توی قسمت Redirect URI این لینک رو بنویسیدhttp://localhost:3000/api/auth/callback/gitlab ?یه نکته ای هم که باید بهش دقت کنید دوستان حواستون باشه که localhost تون روی هر پورتی که هست توی لینکی که هم براتون فرستادم همون رو بزارید. حالا بریم سراغ موارد بعدی، تیک گزینه Confidential بزارید فعال باشه و در آخر در بخش Scopes ، گزینه های api و Read_user و Profile و email رو فعال کنید. خب وارد صفحه ای که میشید بهتون یه Application ID و یه Secret میده حواستون باشه این دوتا رو یه جا ذخیره کنید باهاشون کار داریم. صفحه رو تایید کنید.خب بریم سراغ پروژه ای که با Next13 ایجاد کردیم، در وهله اول دوستان خوبم یه فایل env. ایجاد میکنیم و داخلش این سه تا متغییر رو مینویسمNEXTAUTH_SECRET= ( رمز دلخواه )AUTH_GITLAB_ID= ( Application ID )AUTH_GITLAB_SECRET=( Secret )خاطرتون هست بهتون گفتم Application ID و Secret رو یه جا ذخیره کنید باهاش کارداریم؟! دقیقا همینجاست. براتون در قسمت بالا مشخص کردم که جلو کدوم متغییر، کدوم قسمت رو جایگذاری کنید. و اما NEXTAUTH_SECRET یه رمز دخواه قرار میدید و این رمز باعث هش کردن توکن ها و کوکی هامون میشه من بهتون پیشنهاد میدم برای تولید رمز از کد زیر توی ترمینال تون استفاده کنید openssl rand -base64 32یا از طریق لینک مربوط به خوده Vercel استفاده کنید. مقداری که بهتون داد رو بریزید داخل متغییر NEXTAUTH_SECRET . حالا مرحله بعدی که باید انجام بدید اینه که توی پوشه app (دوستان لازمه عرض کنم من پروژه Nextjs م رو براساس app ایجاد کردم) به صورت زیر پوشه بندی ایجاد کنیدapi/auth/[...nextauth]/route.tsداخل فایل route.ts به این صورت مینویسیمشاید براتون سوال بشه چرا جلوی مقادیر ClientId و clientSecret علامت تعجب (!) گذاشتم ، اگر این علامت رو نزاریم Typescript بهمون به نوعی خطا میده که میگه " داداش این مقادیری که به این دوتا کلید پاس دادی ممکنه undefined باشه هااا! و این که این دوتا کلید اصلا مقدار undefined رو هیچ جوره قبول ندارنااا! ? " خب ما هم اینجا بهش میگیم اصلا جای دووشواری نیست ? یه علامت تعجب میزاریم آخر مقادیر مربوط به کلید هامون، اینطوری بهش میگیم که خیالت راحت این متغییر هایی که ما پاس دادیم به این کلید ها، مقدار دارندر وهله بعد یه پوشه دیگه توی auth ایجاد میکنیم به نام token داخل فایل route.ts این کد رو مینویسیماین کد رو نوشتیم تا زمانی که عملیات احراز هویت با موفقیت انجام شد توکن مورد نظر رو دریافت کنیم تا به وسیله اون اطلاعات مورد نظرمون ( نام کاربری و ایمیل و...) دریافت کنیم.خب دوستان ما تا اینجای کار تمام پیاده سازی های احراز هویت سمت Server رو انجام دادیم حالا میخوایم وقتی همه چی گل و بلبل پیش رفت کاربر هم اون رو ببینه ( به قول یکی از همکارامون " sense" کنه ? ) پس بریم برای پیاده سازی سمت Client.بزارید قبل پیاده سازی فقط قبلش توضیح بدم میخوام چیکار کنم بعد بریم سراغ کد نویسیش ، ببینید دوستان من برای اینکه به کاربر اعلام کنم عملیات احراز هویت ش با موفقیت پیش رفته ، بعد از اینکه توکن رو دریافت کردم و توکن اون مشکلی نداشت ، اطلاعاتی مثل نام و نام خانوادگی ش ( همون نامی که توی حساب کاربری GitLabش ثبت نام کرده) بهش نشون بدم . این قضیه رو یه Custom Hooks که در NextAuth هست به نام useSession برامون فراهم کرده با استفاده از این hook به اطلاعات کاربر ( نام ، ایمیل، آواتار و...) و حتی وضعیت احراز هویت اون (status) میتونیم دسترسی داشته باشیم.فقط قبلش ما یه Provider تعریف کنیم تا بتونییم به اون اطلاعات کاربر هرجای پروژه که خواستیم دسترسی داشته باشیم. خب بریم سراغ پیاده سازیش ، در قدم اول داخل پوشه app همچین چیزی رو پیاده کنیدداخل AuthProvider.tsx در واقع provider رو که صحبتش رو کردیم رو پیاده سازی میکنیم، به این شکلحالا یه component هم درست میکنیم که عملیات signIn و signOut مون رو انجام بده که من طبق ساختاری که در بالا گفتم اسمش رو Signin.tsx قرار دادم و داخلش به این شکل نوشتمدوستان خوبم همونطوری که مشاهده میکنید NextAuth از طریق useSession وضعیتهای (status) مربوط به احراز هویت کاربر ( loading , authenticated , unauthenticated) در اختیارمون قرار میده، منم با توجه به هر وضعیت گفتم که عمل خاصی رو نمایش بده به عنوان مثال توی حالت loading گفتم که یک spinner بهم نشون بده ( با استفاده از کلاس های TailwindCss) و توی حالت authenticated بهم نام کاربر رو نشون بده ( همونی نامی که توی حساب کاربری GitLab ش ثبت نام کرده ) به اضافه اینکه یه دکمه کنارش که عملیات signOut رو انجام میده ، جالبه بدونید برای SignOut کردن هم کافیه فقط توی event مربوط به element تون تابع signOut فراخوانی کنید خوده NextAuth به همین راحتی handle کرده این قضیه رو ? همینطور برای برای signIn، فوق العادس نه ! ? . و در آخر هم برای زمانی که unauthenticated بود دکمه signIn به همراه action مربوطه ش ( چند خط قبل توضیح دادم) رو نمایش بده . به همین راحتی ?حالا وقته اینه که این component رو به همراه provider ی که ایجادش کردیم ، استفاده کنیممن یه فایل layout.tsx داخل app ایجاد کردم و داخلش به این شکل نوشتمخب همونطوری که میبینید دوستان من اومدم یه navbar ایجاد کردم و چون این navbar داخل فایل layout م هست پس یعنی توی کل پروژه قابل مشاهده هست و از طرفی اون provider ی که ایجاد کرده بودیم هم (AuthProvider) همینجا ازش استفاده میکنیم و توی کل پروژه هم به اطلاعات کاربر احراز هویت شده دسترسی داریم. navbar رو هم داخل اون قرارش میدیم و در آخر هم component مربوط به signIn رو داخل یه li قرار دادم و تمام به همین راحتی به همین خوشمزگی?مَخلص کلامجمله پایانی که باید بگم که دوستان مبحث Authentication یا همون احراز هویت یکی از اساسی ترین مباحث سمت امنیت وب سایت تون هست و اگر دغدغه پیاده سازی امنیت سمت پروژه های Nextjs رو دارید یه سیستم احراز هویت با پیاده سازی راحت ( به این معنی بیشتر از 75 ارائه دهنده سرویس که یکیش همینی بود که توی این مقاله پیاده سازی ش کردیم "GitLab" بدون پیچیدگی های بی مورد توی پیاده سازی) منعطف بودن ( به این معنی که توی فریم ورک های خفن مثل Next.js, SolidStart, SvelteKit خیلی شیک با دیتابیس های MySQL, Postgres, MSSQL, MongoDB و... کار میکنه ) ودر آخر امنیت بالا (به این معنی که امنیتش بر اساس CSRF هست و JWT به همراه JWS / JWE / JWK و همچینین همه چی سمت sever پیاده سازی میشه و هیچ چیزی سمت client نیست) NextAuth.js میتونه گزینه مناسبی براتون باشه . خیـــــــــلی ممنون از همتون که تا پایان این مقاله همراه من بودید امیدوارم دوستان براتون مفید باشه . مشتاقانه منتظر سوالات ،نکته ها، انتقادات و پیشنهاداتون هستم رفقا?. مراقب خودتون باشید. روز و روزگارتون خوش??