আমাদের মধ্যে বেশিরভাগই অন্তত একবার অ্যাকাউন্ট পুনরুদ্ধারের প্রক্রিয়াটি অনুভব করেছেন — যখন আমরা একটি পাসওয়ার্ড ভুলে যাই, তখন একটি নতুন তৈরি করতে এবং সিস্টেমে অ্যাক্সেস পুনরুদ্ধারের জন্য পদ্ধতিগুলির প্রয়োজন হয়৷ এই নিবন্ধটি রুটগুলি পরিচালনা করতে এবং প্রয়োজনীয় ক্রিয়াকলাপগুলি সম্পাদন করার জন্য এক্সপ্রেসের পাশাপাশি Node.js, Knex এবং কিছু অপ্রকাশিত সরঞ্জাম ব্যবহার করে এই জাতীয় প্রক্রিয়া বাস্তবায়নের উপর দৃষ্টি নিবদ্ধ করে।
আমরা রাউটার বাস্তবায়ন, URL প্যারামিটার পরিচালনা, প্রমাণ হিসাবে শুধুমাত্র একটি ইমেল বা ফোন নম্বর পাওয়া গেলে ব্যবহারকারীকে কী পাঠাতে হবে তা নির্ধারণ, ইমেল জমা দেওয়া পরিচালনা এবং নিরাপত্তা সংক্রান্ত উদ্বেগগুলিকে কভার করব।
কোডিং এ ডুব দেওয়ার আগে, আমি নিশ্চিত করতে চাই যে আমরা একই কোডবেস নিয়ে কাজ করছি, যা আপনি আমার পাবলিক থেকে অ্যাক্সেস করতে পারবেন
এখন, ভুলে যাওয়া পাসওয়ার্ড প্রবাহের স্কিমাটি দেখুন।
সার্ভারটি পাসওয়ার্ড রিসেট করার জন্য একটি বৈধ লিঙ্ক সহ ব্যবহারকারীর মেলবক্সে ইমেল পাঠানোর জন্য দায়ী থাকবে, এবং টোকেন এবং ব্যবহারকারীর অস্তিত্বও যাচাই করবে।
ইমেল পরিষেবা ব্যবহার শুরু করতে এবং Node.js এর সাথে ইমেল পাঠানো শুরু করতে, আমাদের বিদ্যমান নির্ভরতা ছাড়াও নিম্নলিখিত প্যাকেজগুলি ইনস্টল করতে হবে:
npm i --save nodemailer handlebars
Nodemailer : শক্তিশালী মডিউল যা SMTP বা অন্যান্য পরিবহন ব্যবস্থা ব্যবহার করে সহজেই ইমেল পাঠাতে দেয়।
হ্যান্ডেলবার : হ্যান্ডেলবার জাভাস্ক্রিপ্টের জন্য একটি জনপ্রিয় টেমপ্লেটিং ইঞ্জিন। এটি আমাদের স্থানধারকগুলির সাথে টেমপ্লেটগুলিকে সংজ্ঞায়িত করার অনুমতি দেবে যা রেন্ডার করার সময় ডেটা দিয়ে পূর্ণ হতে পারে।
এখন, আমাদের মাইগ্রেশন তৈরি করতে হবে, তাই আমার ক্ষেত্রে, আমাকে users
টেবিলে একটি নতুন কলাম forgot_password_token
যোগ করতে হবে:
knex migrate:make add_field_forgot_password_token -x ts
এবং উত্পন্ন ফাইলে, আমি কোড সেট করেছি:
import type { Knex } from 'knex'; export async function up(knex: Knex): Promise<void> { return knex.schema.alterTable('users', table => { table.string('forgot_password_token').unique(); }); } export async function down(knex: Knex): Promise<void> { return knex.schema.alterTable('users', table => { table.dropColumn('forgot_password_token'); }); }
ব্যবহারকারীদের টেবিলে ভুলে যাওয়া পাসওয়ার্ড টোকেনের জন্য মাইগ্রেশন
এবং তারপর সর্বশেষ ফাইল স্থানান্তর করুন:
knex migrate:knex
সুতরাং এখন আমরা আমাদের forgot_password_token
users
টেবিলে সেট করতে পারি
পাসওয়ার্ড ভুলে যাওয়া এবং রিসেট করার যুক্তি পরিচালনা করার জন্য দায়ী কন্ট্রোলারদের পরিচালনা করতে, আমাদের অবশ্যই দুটি রুট স্থাপন করতে হবে। প্রথম রুটটি ভুলে যাওয়া পাসওয়ার্ড প্রক্রিয়া শুরু করে, যখন দ্বিতীয়টি রিসেট প্রক্রিয়া পরিচালনা করে, যাচাইয়ের জন্য URL-এ একটি টোকেন প্যারামিটার আশা করে। এটি বাস্তবায়ন করতে, src/routes/
ডিরেক্টরির মধ্যে forgotPasswordRouter.ts
নামে একটি ফাইল তৈরি করুন এবং নিম্নলিখিত কোডটি সন্নিবেশ করুন:
import { Router } from 'express'; import { forgotPasswordController } from 'src/controllers/forgotPasswordController'; import { resetPasswordController } from 'src/controllers/resetPasswordController'; export const forgotPasswordRouter = Router(); forgotPasswordRouter.post('/', forgotPasswordController); forgotPasswordRouter.post('/reset/:token', resetPasswordController);
পাসওয়ার্ড রাউটার ভুলে গেছি
দুটি কন্ট্রোলার ইমেল পাঠানো এবং পাসওয়ার্ড রিসেট করার জন্য যুক্তি পরিচালনা করবে।
ক্লায়েন্ট যখন তার পাসওয়ার্ড ভুলে যায় তখন তার কোনো সেশন থাকে না, যার মানে আমরা ইমেল বা অন্য কোনো নিরাপত্তা শনাক্তকারী ছাড়া ব্যবহারকারীর ডেটা পেতে পারি না। আমাদের ক্ষেত্রে, আমরা একটি পাসওয়ার্ড রিসেট পরিচালনা করার জন্য একটি ইমেল পাঠাচ্ছি। যে যুক্তি আমরা কন্ট্রোলার মধ্যে সেট করতে যাচ্ছেন.
forgotPasswordRouter.post('/', forgotPasswordController);
'পাসওয়ার্ড ভুলে গেছেন?' লগইন ফর্মের নীচের লিঙ্কটি সাধারণত লগইন ফর্মের কোন ক্লায়েন্টের UI-তে থাকে? এটিতে ক্লিক করা আমাদেরকে একটি ভিউতে নির্দেশ করে যেখানে আমরা একটি পাসওয়ার্ড রিসেট করার অনুরোধ করতে পারি। আমরা কেবল আমাদের ইমেল ইনপুট করি, এবং নিয়ামক সমস্ত প্রয়োজনীয় প্রক্রিয়া পরিচালনা করে। আসুন নিম্নলিখিত কোড পরীক্ষা করা যাক:
import { Request, Response } from 'express'; import { UserModel } from 'src/models/UserModel'; import type { User } from 'src/@types'; import { TokenService } from 'src/services/TokenService'; import { EmailService } from 'src/services/EmailService'; export const forgotPasswordController = async (req: Request, res: Response) => { try { const { email, }: { email: string; } = req.body; const user = await UserModel.findByEmail(email); if (user) { const token = await TokenService.sign( { id: user.id, }, { expiresIn: '1 day', } ); await user.context.update({ forgot_password_token: token }); await EmailService.sendPasswordResetEmail(email, token); } return res.sendStatus(200); } catch (error) { return res.sendStatus(500); } };
পাসওয়ার্ড কন্ট্রোলার ভুলে গেছেন
শরীর থেকে, আমরা একটি ইমেল পেতে যাচ্ছি, এবং তারপর আমরা UserModel.findByEmail
ব্যবহার করে ব্যবহারকারীকে খুঁজে পাব। ব্যবহারকারী থাকলে, আমরা TokenService.sign
ব্যবহার করে একটি JWT টোকেন তৈরি করি এবং টোকেনটি ব্যবহারকারীর কাছে সংরক্ষণ করি forgot_password_token
এর মেয়াদ 1 দিনের মধ্যে। তারপরে আমরা একটি টোকেন সহ একটি সঠিক লিঙ্ক সহ ইমেলে বার্তাটি পাঠাব যেখানে ব্যবহারকারী তার পাসওয়ার্ড পরিবর্তন করতে সক্ষম হবে।
ইমেল পাঠাতে সক্ষম হওয়ার জন্য, আমাদের নতুন ইমেল ঠিকানা তৈরি করতে হবে যা একজন প্রেরক হবে।
চলুন Google-এ যাই, একটি নতুন ইমেল অ্যাকাউন্ট তৈরি করতে, এবং তারপরে, অ্যাকাউন্ট তৈরি হয়ে গেলে, আপনার Google অ্যাকাউন্ট পরিচালনা করুন লিঙ্কে এগিয়ে যান। আপনি অবতারে ক্লিক করে উপরের ডানদিকে এটি খুঁজে পেতে পারেন। তারপরে, বাম মেনুতে, সুরক্ষা আইটেমটিতে ক্লিক করুন এবং তারপরে 2-পদক্ষেপ যাচাইকরণ টিপুন। নীচে আপনি অ্যাপ পাসওয়ার্ড বিভাগটি পাবেন, তীরটিতে ক্লিক করুন:
যে নামটি ব্যবহার করতে হবে সেটি ইনপুট করুন। আমার ক্ষেত্রে, আমি Nodemailer
সেট করে Create টিপুন।
জেনারেট করা পাসওয়ার্ডটি কপি করুন এবং আপনার .env
ফাইলে সেট করুন। আমাদের দুটি ভেরিয়েবল ফাইল সেট করতে হবে:
MAIL_USER="[email protected]" MAIL_PASSWORD="vyew hzek avty iwst"
অবশ্যই, info@company_name.com
এর মতো একটি সঠিক ইমেল পেতে, আপনাকে AWS SES বা অন্য কোনো পরিষেবার সাথে Google Workspace বা AWS Amazon WorkMail সেট আপ করতে হবে। কিন্তু আমাদের ক্ষেত্রে, আমরা বিনামূল্যে একটি সাধারণ Gmail অ্যাকাউন্ট ব্যবহার করছি।
.env
ফাইল প্রস্তুত করে, আমরা ইমেল পাঠানোর জন্য আমাদের পরিষেবা সেট আপ করতে প্রস্তুত। নিয়ামক আমাদের বার্তার জন্য জেনারেট করা টোকেন এবং প্রাপকের ইমেল ঠিকানা সহ পরিষেবাটি ব্যবহার করবে।
await EmailService.sendPasswordResetEmail(email, token);
আসুন src/services/EmailService.ts
তৈরি করি এবং পরিষেবাটির জন্য ক্লাস সংজ্ঞায়িত করি:
export class EmailService {}
এবং এখন প্রাথমিক তথ্য হিসাবে, আমাকে nodemailer
এর সাথে ব্যবহার করার জন্য পরিবেশ পেতে হবে:
import process from 'process'; import * as nodemailer from 'nodemailer'; import * as dotenv from 'dotenv'; dotenv.config(); export class EmailService { private static transporter: nodemailer.Transporter; private static env = { USER: process.env.MAIL_USER, PASS: process.env.MAIL_PASSWORD, }; }
ইমেল পরিষেবা
আমাদের সেবা শুরু করার যত্ন নিতে হবে। আমি এটা সম্পর্কে আমার পূর্ববর্তী আগে লিখেছিলাম
import { TokenService } from 'src/services/TokenService'; import { RedisService } from 'src/services/RedisService'; import { EmailService } from 'src/services/EmailService'; export const initialize = async () => { await RedisService.initialize(); TokenService.initialize(); EmailService.initialize(); };
পরিষেবা শুরু করা হচ্ছে
এখন, আমাদের EmailService
ক্লাসের মধ্যে প্রারম্ভিকতা তৈরি করে এগিয়ে যাওয়া যাক:
import process from 'process'; import * as nodemailer from 'nodemailer'; import * as dotenv from 'dotenv'; dotenv.config(); export class EmailService { private static transporter: nodemailer.Transporter; private static env = { USER: process.env.MAIL_USER, PASS: process.env.MAIL_PASSWORD, }; public static initialize() { try { EmailService.transporter = nodemailer.createTransport({ service: 'gmail', auth: { user: this.env.USER, pass: this.env.PASS, }, }); } catch (error) { console.error('Error initializing email service'); throw error; } } }
ইমেল পরিষেবা সূচনা
nodemailer
লাইব্রেরি দ্বারা প্রদত্ত একটি পদ্ধতি, প্রাথমিককরণ nodemailer.createTransport()
আছে। এটি একটি ট্রান্সপোর্টার অবজেক্ট তৈরি করে যা আমাদের ইমেল পাঠাতে ব্যবহার করা হবে। পদ্ধতিটি একটি বিকল্প অবজেক্টকে একটি যুক্তি হিসাবে গ্রহণ করে যেখানে আপনি ট্রান্সপোর্টারের জন্য কনফিগারেশনের বিশদ উল্লেখ করেন।
আমরা Google: service: 'gmail'
ইমেল পরিষেবা প্রদানকারীকে নির্দিষ্ট করে। Nodemailer বিভিন্ন ইমেল পরিষেবা প্রদানকারীর জন্য অন্তর্নির্মিত সমর্থন প্রদান করে, এবং gmail
নির্দেশ করে যে পরিবহণকারীকে Gmail এর SMTP সার্ভারের সাথে কাজ করার জন্য কনফিগার করা হবে।
প্রমাণীকরণ auth
জন্য, ইমেল পরিষেবা প্রদানকারীর SMTP সার্ভারে অ্যাক্সেস করার জন্য প্রয়োজনীয় শংসাপত্রগুলি সেট করা প্রয়োজন৷
user
জন্য ইমেল ঠিকানা সেট করা উচিত যেখান থেকে আমরা ইমেল পাঠাতে যাচ্ছি, এবং সেই পাসওয়ার্ডটি অ্যাপ পাসওয়ার্ড থেকে গুগল অ্যাকাউন্টে তৈরি করা হয়েছে।
এখন, আমাদের পরিষেবার শেষ অংশ সেট করা যাক:
import process from 'process'; import * as nodemailer from 'nodemailer'; import * as dotenv from 'dotenv'; import { generateAttachments } from 'src/helpers/generateAttachments'; import { generateTemplate } from 'src/helpers/generateTemplate'; import { getHost } from 'src/helpers/getHost'; dotenv.config(); export class EmailService { // ...rest code public static async sendPasswordResetEmail(email: string, token: string) { try { const host = getHost(); const template = generateTemplate<{ token: string; host: string; }>('passwordResetTemplate', { token, host }); const attachments = generateAttachments([{ name: 'email_logo' }]); const info = await EmailService.transporter.sendMail({ from: this.env.USER, to: email, subject: 'Password Reset', html: template, attachments, }); console.log('Message sent: %s', info.messageId); } catch (error) { console.error('Error sending email: ', error); } } }
পাসওয়ার্ড রিসেট ইমেল পাঠান
এগিয়ে যাওয়ার আগে, ক্লায়েন্ট কখন একটি ইমেল পায় তার জন্য উপযুক্ত হোস্ট নির্ধারণ করা অত্যন্ত গুরুত্বপূর্ণ। ইমেইল বডিতে একটি টোকেন সহ একটি লিঙ্ক স্থাপন করা অপরিহার্য।
import * as dotenv from 'dotenv'; import process from 'process'; dotenv.config(); export const getHost = (): string => { const isProduction = process.env.NODE_ENV === 'production'; const protocol = isProduction ? 'https' : 'http'; const port = isProduction ? '' : `:${process.env.CLIENT_PORT}`; return `${protocol}://${process.env.WEB_HOST}${port}`; };
হোস্ট পান
টেমপ্লেটের জন্য, আমি handlebars
ব্যবহার করছি এবং এর জন্য আমাদের src/temlates/passwordResetTemplate.hbs
এ আমাদের প্রথম HTML টেমপ্লেট তৈরি করতে হবে:
<!-- passwordResetTemplate.hbs --> <html lang='en'> <head> <style> a { color: #372aff; } .token { font-weight: bold; } </style> <title>Forgot Password</title> </head> <body> <p>You requested a password reset. Please use the following link to reset your password:</p> <a class='token' href="{{ host }}/reset-password/{{ token }}">Reset Password</a> <p>If you did not request a password reset, please ignore this email.</p> <img src="cid:email_logo" alt="Email Logo"/> </body> </html>
পাসওয়ার্ড রিসেট টেমপ্লেট
এবং এখন আমরা সাহায্যকারীর সাথে এই টেমপ্লেটটি পুনরায় ব্যবহার করতে পারি:
import path from 'path'; import fs from 'fs'; import handlebars from 'handlebars'; export const generateTemplate = <T>(name: string, props: T): string => { const templatePath = path.join(__dirname, '..', 'src/templates', `${name}.hbs`); const templateSource = fs.readFileSync(templatePath, 'utf8'); const template = handlebars.compile(templateSource); return template(props); };
টেমপ্লেট হেল্পার তৈরি করুন
আমাদের ইমেল উন্নত করতে, আমরা এমনকি সংযুক্তি অন্তর্ভুক্ত করতে পারি। এটি করতে, src/assets
ফোল্ডারে email_logo.png
ফাইলটি যোগ করুন। তারপরে আমরা নিম্নলিখিত সহায়ক ফাংশন ব্যবহার করে ইমেলের মধ্যে এই ছবিটি রেন্ডার করতে পারি:
import path from 'path'; import { Extension } from 'src/@types/enums'; type AttachmentFile = { name: string; ext?: Extension; cid?: string; }; export const generateAttachments = (files: AttachmentFile[] = []) => files.map(file => { const ext = file.ext || Extension.png; const filename = `${file.name}.${ext}`; const imagePath = path.join(__dirname, '..', 'src/assets', filename); return { filename, path: imagePath, cid: file.cid || file.name, }; });
সংযুক্তি সাহায্যকারী তৈরি করুন
এই সমস্ত সাহায্যকারী সংগ্রহ করার পরে, আমাদের ব্যবহার করে ইমেল পাঠাতে সক্ষম হতে হবে:
const info = await EmailService.transporter.sendMail({ from: this.env.USER, to: email, subject: 'Password Reset', html: template, attachments, });
এই পদ্ধতিটি শালীন পরিমাপযোগ্যতা প্রদান করে, পরিষেবাটিকে বিভিন্ন বিষয়বস্তু সহ ইমেল পাঠানোর জন্য বিভিন্ন পদ্ধতি নিয়োগ করতে সক্ষম করে।
এখন, আমাদের রাউটার দিয়ে কন্ট্রোলারটিকে ট্রিগার করার চেষ্টা করুন এবং ইমেল পাঠান। যে জন্য, আমি ব্যবহার করছি
কনসোল আপনাকে বলবে যে বার্তাটি পাঠানো হয়েছে:
Message sent: <1k96ah55-c09t-p9k2–[email protected]>
ইনবক্সে নতুন বার্তাগুলির জন্য চেক করুন:
পাসওয়ার্ড রিসেট করার লিঙ্কটিতে টোকেন এবং হোস্ট থাকতে হবে:
http://localhost:3000/reset-password/<token>
পোর্ট 3000
এখানে নির্দিষ্ট করা হয়েছে কারণ এই বার্তাটি উন্নয়ন প্রক্রিয়ার সাথে সম্পর্কিত। এটি নির্দেশ করে যে পাসওয়ার্ড রিসেটের জন্য ফর্মগুলি পরিচালনার জন্য দায়ী ক্লায়েন্টও উন্নয়ন পরিবেশের মধ্যে কাজ করবে৷
টোকেনটিকে টোকেনসার্ভিসের মাধ্যমে কন্ট্রোলার সাইডে যাচাই করতে হবে যেখান থেকে আমরা সেই ইমেলটি পাঠানো ব্যবহারকারীকে পেতে পারি। টোকেন ব্যবহার করে রাউটারটি পুনরুদ্ধার করা যাক:
forgotPasswordRouter.post('/reset/:token', resetPasswordController);
কন্ট্রোলার শুধুমাত্র পাসওয়ার্ড আপডেট করবে যদি টোকেনটি বৈধ হয় এবং মেয়াদ শেষ না হয়, মেয়াদ শেষ হওয়ার সময় এক ঘন্টা সেট করা হয়। এই কার্যকারিতা বাস্তবায়ন করতে, src/controllers/
ফোল্ডারে নেভিগেট করুন এবং নিম্নলিখিত কোড ধারণকারী resetPasswordController.ts
নামে একটি ফাইল তৈরি করুন:
import bcrypt from 'bcrypt'; import { Request, Response } from 'express'; import { TokenService } from 'src/services/TokenService'; import { UserModel } from 'src/models/UserModel'; import type { User } from 'src/@types'; export const resetPasswordController = async (req: Request, res: Response) => { try { const token = req.params.token; if (!token) { return res.sendStatus(400); } const userData = await TokenService.verify<{ id: number }>(token); const user = await UserModel.findOneById<User>(userData.id); if (!user) { return res.sendStatus(400); } const newPassword = req.body.password; if (!newPassword) { return res.sendStatus(400); } const hashedPassword = await bcrypt.hash(newPassword, 10); await UserModel.updateById(user.id, { password: hashedPassword, passwordResetToken: null }); return res.sendStatus(200); } catch (error) { const errors = ['jwt malformed', 'TokenExpiredError', 'invalid token']; if (errors.includes(error.message)) { return res.sendStatus(400); } return res.sendStatus(500); } };
পাসওয়ার্ড কন্ট্রোলার রিসেট করুন
এই কন্ট্রোলার টোকেনটি পাবে, এটি যাচাই করবে, ডিক্রিপ্ট করা ডেটা থেকে ব্যবহারকারীর আইডি বের করবে, সংশ্লিষ্ট ব্যবহারকারীকে পুনরুদ্ধার করবে, অনুরোধের বডিতে ক্লায়েন্টের পাঠানো নতুন পাসওয়ার্ড অর্জন করবে এবং ডাটাবেসে পাসওয়ার্ড আপডেট করতে এগিয়ে যাবে। শেষ পর্যন্ত, এটি ক্লায়েন্টকে নতুন পাসওয়ার্ড ব্যবহার করে লগ ইন করতে সক্ষম করে।
ইমেল পরিষেবার মাপযোগ্যতা বিভিন্ন পদ্ধতির মাধ্যমে প্রদর্শিত হয়, যেমন নিশ্চিতকরণ বা সাফল্যের বার্তা পাঠানো, যেমন একটি পাসওয়ার্ড আপডেট নির্দেশ করে এবং পরবর্তী লগইন সক্ষম করে। যাইহোক, পাসওয়ার্ড পরিচালনা করা একটি বড় চ্যালেঞ্জ, বিশেষ করে যখন অ্যাপ্লিকেশন নিরাপত্তা বাড়ানো অপরিহার্য।
টোকেন তুলনা, ইমেল এবং পাসওয়ার্ড যাচাইকরণের মতো পাসওয়ার্ড পরিবর্তনের অনুমতি দেওয়ার আগে অতিরিক্ত চেক সহ নিরাপত্তা জোরদার করার জন্য অনেকগুলি বিকল্প উপলব্ধ রয়েছে।
আরেকটি বিকল্প হল একটি পিন কোড সিস্টেম বাস্তবায়ন করা, যেখানে সার্ভারের পাশে বৈধতার জন্য ব্যবহারকারীর ইমেলে একটি কোড পাঠানো হয়। এই প্রতিটি পদক্ষেপের জন্য ইমেল পাঠানোর ক্ষমতার ব্যবহার প্রয়োজন।
সমস্ত বাস্তবায়িত কোড আপনি খুঁজে পেতে পারেন
অনুগ্রহ করে এই বিল্ডের সাথে যেকোন পরীক্ষা-নিরীক্ষা চালাতে নির্দ্বিধায়, এবং এই বিষয় সম্পর্কে আপনি কোন দিকগুলির প্রশংসা করেন সে সম্পর্কে আপনার প্রতিক্রিয়া ভাগ করুন৷ তোমাকে অনেক ধন্যবাদ.
এখানে, আপনি বেশ কয়েকটি রেফারেন্স খুঁজে পেতে পারেন যা আমি এই নিবন্ধে ব্যবহার করেছি:
এছাড়াও এখানে প্রকাশিত