جلد یک تجربگی : پیاده سازی ورود و ثبت نام با نود جی اس

سلام بعد از سه سال دوباره با یه پست شاید مفید اومدم خدمتتون. صرفا دوس دارم یاد گرفته هامو اشتراک بذارم تا خودمم یه محکی زده باشم.حرف بسه بریم سراغ کار.خب اول همه توضیح بدیم که چه کاری قراره انجام بدیم.قراره که روند ثبت نام و ورود کاربر رو کار کنیم با نود جی اس ، اکسپرس صد البته Mongoose . چیا کلا قراره پیاده سازی بشه ثبت نام کاربر و لاگین کاربر ، ریست کردن پسورد ، ریست کردن توکن ، ایمیل کردن ریست پسورد ، محافظت از مسیر های یوزر ، نقش کاربر ادمین یا restrict کردن ها و کار با توکن و کوکی و ذخیره سازی کلی چیز میز.البته فک نکنم همش توی یه مقاله حوصله سر بر نشه و تقسیمش میکنم به سلسله ای از مقالات.:))هشدار که شاید کامنت گذاری ها توی متن و اسم گذاری ها باب میل سنیور ها نباشه.و اینکه ارور هندلینگم خودتون هندل کنید دیگه .:))چیزایی که فعلا احتیاج داریم ایناس که با npm نصب شن : ,bcryptjs ,express ,jsonwebtoken ,mongoose ,validator, nodemailerیه سری فایل هم باید ساخته بشه که بخش بخش باهاش میریم جلو : فایل اول فایل userModel.js که قرار مدل اسکیمای یوزر رو توش بسازیم: به این شکل با کد زیر: const mongoose = require(&quotmongoose&quot); const validator = require(&quotvalidator&quot); const bcrypt = require(&quotbcryptjs&quot); const userSchema = new mongoose.Schema({ name: { type: String, required: [true, &quotPlease tell us your name!&quot], }, email: { type: String, required: [true, &quotPlease provide your email&quot], unique: true, lowercase: true, validate: [validator.isEmail, &quotPlease provide a valid email&quot], }, photo: String, role: { type: String, enum: [&quotadmin&quot, &quotuser&quot, &quottour-lead&quot, &quottour-guied&quot], default: &quotuser&quot, }, password: { type: String, required: [true, &quotPlease provide a password&quot], minlength: 8, select: false, }, passwordConfirm: { type: String, required: [true, &quotPlease confirm your password&quot], validate: { validator: function (el) { return el ==this.password}, message: &quotconfirm password is incorrect&quot, } } passwordChangeAt: Date}); خب راجع به مدل بگم که 7 تا فیلده : نام ،ایمیل ، پسورد ، تایید پسورد،نقش کاربر، عکس پروفایل و تاریخ تغییر پسورد فعلا البته بعدا باز اضافه میشه بهشون.از validator توی ایمیل استفاده کردیم برای صحتش. و توی تایید ایمیل هم یه فانکشنی برای ولیدیت نوشتیم.خب حالا که مدل رو ساختیم میریم سراغ فایل server.js شروع برنامه .چیز خاصی توش نیست که بخوام کدش رو بذارم فقط کانفیگ سرور و منگو دی بی و پورت و اینا همین.توی فایل app.js هم همون چیزایی که برای شروع هست فقط روت یوزر رو ست میکنیم: app.use(&quot/api/v1/users&quot, userRouter);خب حالا باید دوتا فایل بسازیم اولی برای احراز یوزر کنترلر authController و دومی برای یوزر روترuserRouter.توی فایل اول یعنی authController دوتا میدلور داریم. یکی برای ثبت نام به اسم signUp و دیگری برای ورود کاربر.فعلا خالی خالی بسازیم و اکسپورت کنیم چون توی یوزر روتر کار داریم .بعد تک تک هرکودوم رو میریم جلو.میدلور هارو که توی کنترلر ساختیم توی فایل یوزر روتر ست میکنیم.یوزر روتر:::const express = require(&quotexpress&quot); const authController = require(&quot../controllers/authController&quot); const router = express.Router(); router.post(&quot/signup&quot, authController.signUp); ایناهاش router.post(&quot/login&quot, authController.logIn); ایناهاش module.exports = router;خب حالا همه چی آمادس بریم سر وقت فایل کنترلر مون:مدل و jwt رو ایمپورت میکنیم تا ازش استفاده کنیم اسمه مدلمون هم User هست.onst User = require(&quot../model/userModel&quot); const jwt = require(&quotjsonwebtoken&quot);یه فانکشنی مینویسیم برای ایجاد توکن نا برامون توکن تولید کنه آیدی کاربر رو به عنوان ورودی میگیره.const signToken = (id) => { return jwt.sign({ id }, &quotnew_secret_key_foobar&quot, { expiresIn: &quot30d&quot, });};سه تا مقدار میتونیم به این متد sign بدیم . یکیش آی دی که از پارامترمون گرفتیم دومی کلید سکرت که من اینجا اینو گذاشتم ولی شما اینو نذارید :)) سومی هم مدت زمان ماندگاری توکنه .که به روز و دقیقه وساعت اینا میتونید وارد کنید که من اینجا دادم 30 روز.خیلی بهتره که کلید سکرت و اینجور موارد رو توی فایل config.env وارد کنید و بعد با دات انو ازش استفاده کنید.مرحله بعدی ساخت فانکشن ثبت نام هست : کدو ببین و بعد توضیحات رو ببین : exports.signUp = async (req, res) => { const newUser = await User.create({ name: req.body.name, email: req.body.email, password: req.body.password, passwordConfirm: req.body.passwordConfirm, passwordChangeAt: req.body.passwordChangeAt, role: req.body.role,}); const token = signToken(newUser._id); res.status(201).json({ status: &quotok&quot, token, data: { newUser, },});};از مدل User و متد create استفاده میکنیم و با استفاده از req.body یه کاربر جدید میسازیم. بعد یه ثابت میسازیم به اسم توکن و فانکشن sign ور صدا میزنیم و حالا که آی دی کاربر رو داریم آی دی رو بهش میدیم.بعد هم یوزر جدید و توکن رو به آبجکت جیسون میدیم.توجه کنید که ارور هندلینگ رو پیاده سازی کنید حتما.خب حالا مرحله بعدی که داریم اینکه قبل از اینکه پسورد توی دیتابیس ذخیره بشه اونو رمزنگاری کنیم.چطوری اینکارو بکنیم؟ میتونیم از متد توی فایل مدل یوزر استفاده کنیم. و از قلاب .pre توی فایل مدل یوزرمون که اول همین مقاله هست این کد رو اضافه میکنیم : //encrypt password with bcrypt hash userSchema.pre(&quotsave&quot, async function (next) { if (!this.isModified(&quotpassword&quot)) return next(); this.password = await bcrypt.hash(this.password, 12); this.passwordConfirm = undefined; next(); });بی کریپت جی اس bcryptjs رو قبلا نصب کردیم از هوک .pre و save استفاده می کنیم و یک عدد کالبک فانکشن : اول بررسی میکنم ببینم که تغییری توی داکیومنت داده شده یا نه با this.isModified بعد پسوردم رو مقدار جدیدی میدم که مقدار جدیدش همون پسورده که با بی کریپت هش کردیم.در آخر هم نمیخوام که تایید پسوردم توی دیتابیس ذخیره بشه من فقط برای ولیدیت کردن احتیاجش دارم برای همین مقدارش رو آندیفاین میذارم.قبلا توی خود مدل من با یه فانکشن ولیدتش کردم. خب حالا اگر کد رو سیو کنیم میبینیم که به راحتی میره توی دیتابیس ذخیره میشه.نکته دیگه که فعلا به role یوزر کاری نداریم بعدا برای محدودیت ایجاد کردن ازش استفاده میکنیم.البته فعلا به صورت دیفالت نقش رو user تعیین میکنه.بعدا با ادمین کار میکنیم.به نظرم برای این قسمت کافیه.توی قسمت بعد لاگین یا ورود رو پیاده سازی کنیم.با توکن بیشتر کار کنیم و ببینیم داستان توکن و پسورد و لاگین چطوریه.باز نکته اینکه اگر اشتباهات املایی داشتم یا جایی از ه کسره استفاده کردم یا فانکشنی رو کال بک گفتم یا برعکس یا چیزی باشد که اصلاح شود.