আমার Node.js অ্যাপ্লিকেশনগুলির জন্য একটি দ্রুত, স্বজ্ঞাত, এবং সুবিন্যস্ত প্রমাণীকরণ সমাধানের জন্য আমার অনুসন্ধানে, আমি কার্যকারিতার সাথে আপস না করে দ্রুত বাস্তবায়নের দাবিতে এমন পরিস্থিতির সম্মুখীন হয়েছি।
ব্যবহারকারী সাইনআপ এবং লগইন থেকে শুরু করে ভুলে যাওয়া পাসওয়ার্ড পরিচালনা, ব্যবহারকারীর ডেটা আপডেট করা এবং এমনকি অ্যাকাউন্ট মুছে ফেলা পর্যন্ত, আমি একটি ব্যাপক সমাধান চেয়েছি যা এই প্রয়োজনীয় ব্যবহারকারীর মিথস্ক্রিয়াগুলির মাধ্যমে নির্বিঘ্নে নেভিগেট করে।
এইভাবে, আমার নিবন্ধটির লক্ষ্য হল সুনির্দিষ্টভাবে উপস্থাপন করা - একটি সুসংহত পদ্ধতির মাধ্যমে প্রমাণীকরণ এবং ক্যাশিং বাস্তবায়নের জন্য সুস্পষ্ট পদ্ধতিগুলিকে একীভূত করা, একটি শক্তিশালী এবং দক্ষ ব্যবহারকারীর প্রবাহ নিশ্চিত করা।
এখানে, আমরা মৌলিক ইনস্টলেশন পদ্ধতি এবং মডেল তৈরিকে বাইপাস করব, সরাসরি প্রমাণীকরণের জটিলতা এবং ব্যবহারকারীর প্রবাহের উপর নির্ভর করে। সেটআপের জন্য প্রয়োজনীয় সংস্থানগুলিতে নির্বিঘ্ন অ্যাক্সেস নিশ্চিত করে, আমরা নিবন্ধ জুড়ে কনফিগারেশন ফাইলগুলি পেতে সমস্ত প্রয়োজনীয় লিঙ্কগুলি অন্তর্ভুক্ত করব।
এই বাস্তবায়নের জন্য, আমরা Knex, Express এবং Redis-এর পাশাপাশি Node.js সংস্করণ 20.11.1 ব্যবহার করব। উপরন্তু, আমরা আমাদের ডাটাবেস হিসাবে PostgreSQL ব্যবহার করব, যা নির্বিঘ্ন ব্যবস্থাপনার জন্য ডকার ব্যবহার করে কন্টেইনারাইজড এবং সাজানো হবে।
আমাদের অ্যাপ্লিকেশনটির নাম হবে user-flow-boilerplate
। আসুন সেই ফোল্ডারটি তৈরি করি এবং ভিতরে npm init -y
চালান বেসিক package.json
জেনারেট করতে
{ "name": "user-flow-boilerplate", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC" }
প্রাথমিক package.json
পরবর্তী ধাপ হল প্রয়োজনীয় নির্ভরতা যোগ করা:
নির্ভরতা : npm i -S bcrypt body-parser cors dotenv express jsonwebtoken knex pg redis validator
dev নির্ভরতা :
npm i -D @babel/core @babel/eslint-parser @babel/plugin-transform-class-properties @babel/plugin-transform-runtime @babel/preset-env @babel/preset-typescript @faker-js/faker @types/bcrypt @types/body-parser @types/cors @types/express @types/jest @types/jsonwebtoken @types/node @types/node-cron @types/validator @typescript-eslint/eslint-plugin @typescript-eslint/parser babel-jest cross-env eslint eslint-config-prettier eslint-plugin-prettier jest nodemon npm-run-all prettier ts-jest ts-loader ts-node tsconfig-paths tslint typescript webpack webpack-cli webpack-node-externals
এবং স্ক্রিপ্ট যোগ করুন যা আমাদের অ্যাপ্লিকেশন তৈরি এবং চালাবে:
"scripts": { "start": "NODE_ENV=production node dist/bundle.js", "build": "NODE_ENV=production webpack --config webpack.config.js", "dev": "cross-env NODE_ENV=development && npm-run-all -p dev:*", "dev:build": "webpack --config webpack.config.js --watch", "dev:start": "nodemon --watch dist --exec node dist/bundle.js", "test": "NODE_ENV=test jest --config ./jest.config.js", "lint": "eslint ./src -c .eslintrc.json" },
আমাদের অ্যাপ্লিকেশনের সুচারু লঞ্চ নিশ্চিত করতে, একটি src
ফোল্ডার তৈরি করা এবং আমাদের প্রাথমিক এন্ট্রি পয়েন্ট ফাইল, index.ts
, এটির মধ্যে স্থাপন করা অপরিহার্য।
require('dotenv').config(); import process from 'process'; import express from 'express'; import bodyParser from 'body-parser'; import cors from 'cors'; const app = express(); const PORT = process.env.PORT || 9999; app.use(bodyParser.json()); app.use(cors()); app.get('/api/v1/health', (req, res) => res.status(200).json({ message: 'OK' })); (async () => { try { app.listen(PORT, async () => { console.log(`Server is running on port ${PORT}`); }); } catch (error) { console.error('Failed to start server:', error); process.exit(1); } })();
এন্ট্রিপয়েন্ট ফাইল
বিকাশের জন্য, আমাদের typscript
, lint
, jest
, bable
, prettier
, nodemon
এর জন্য সেটিংস থাকতে হবে। আমি নিম্নলিখিত নিবন্ধে বর্ণিত সেই সমস্ত ফাইলগুলি: এক্সপ্রেস-এ পোস্টগ্রেস এবং নক্স সহ একটি Node.js সার্ভার তৈরি করা ।
সমস্ত সেটিংস কনফিগার করার পরে এবং এন্ট্রি পয়েন্ট তৈরি করার পরে, npm run dev
চালানোর ফলে সার্ভার শুরু করা উচিত এবং আপনি নিম্নলিখিতগুলির মতো আউটপুট দেখতে পাবেন:
./src/index.ts 1.7 KiB [built] [code generated] external "dotenv" 42 bytes [built] [code generated] external "process" 42 bytes [built] [code generated] external "express" 42 bytes [built] [code generated] external "body-parser" 42 bytes [built] [code generated] external "cors" 42 bytes [built] [code generated] webpack 5.90.3 compiled successfully in 751 ms [nodemon] restarting due to changes... [nodemon] starting `node dist/bundle.js` Server is running on port 9999
পরবর্তী, নেভিগেট করুনGET
অনুরোধ যোগ করুন, cmd + E
টিপুন (ম্যাকে, তবে কীগুলি আপনার OS এর উপর নির্ভর করে), এবং এটিকে health
হিসাবে নাম দিন।
URL এর জন্য এন্টার যোগ করুন: {{BASE_URI}}/health
। BASE_URI
এর জন্য, একটি নতুন ভেরিয়েবল যোগ করুন যা আপনি সংগ্রহ জুড়ে ব্যবহার করতে যাচ্ছেন: http://localhost:9999/api/v1
তারপরে, কেবল 'পাঠান' বোতামটি ক্লিক করুন, এবং আপনার প্রতিক্রিয়া বডিটি পর্যবেক্ষণ করা উচিত:
{ "message": "OK" }
এগিয়ে যাওয়ার আগে, আমাদের ডাটাবেস আপ এবং চলমান থাকা অত্যন্ত গুরুত্বপূর্ণ। আমরা docker-compose
দিয়ে এটি চালু করে এটি সম্পন্ন করব। ডাটাবেস অ্যাক্সেস এবং পরিচালনা করতে, আপনি বিভিন্ন উন্নয়ন প্ল্যাটফর্ম ব্যবহার করতে পারেন
ব্যক্তিগতভাবে, আমি ব্যবহার করতে পছন্দ করি
আমাদের প্রয়োজনীয় কী, পাসওয়ার্ড এবং পরীক্ষার নাম সহ .env
ফাইল দরকার:
PORT=9999 WEB_HOST="localhost" # DB DB_HOST="localhost" DB_PORT=5432 DB_NAME="user_flow_boilerplate" DB_USER="username_123" DB_PASSWORD="SomeParole999" # User DEFAULT_PASSWORD="SomeParole999" JWT_SECRET="6f1d7e9b9ba56476ae2f4bdebf667d88eeee6e6c98c68f392ed39f7cf6e51c5a" # Test User TEST_EMAIL="[email protected]" TEST_USERNAME="test_username" TEST_PASSWORD="SomeParole999" # Redis REDIS_HOST="localhost" REDIS_PORT=6379 REDIS_DB=0 REDIS_PASSWORD="SomeParole999"
ডাটাবেসের সাথে সংযোগের জন্য env, রেডিস, এবং বীজের জন্য পরীক্ষার মান
ভয় পাবেন না, আমি এলোমেলোভাবে JWT_SECRET
তৈরি করেছি যাতে এটি আরও খাঁটি উপায়ে ব্যাখ্যা করা যায়। সুতরাং, প্রকল্পের মূলে একটি docker-compose.yml
ফাইল তৈরি করা যাক:
version: '3.6' volumes: data: services: database: build: context: . dockerfile: postgres.dockerfile image: postgres:latest container_name: postgres environment: TZ: Europe/Madrid POSTGRES_DB: ${DB_NAME} POSTGRES_USER: ${DB_USER} POSTGRES_PASSWORD: ${DB_PASSWORD} networks: - default volumes: - data:/var/lib/postgresql/data ports: - "5432:5432" restart: unless-stopped redis: image: redis:latest container_name: redis command: redis-server --requirepass ${REDIS_PASSWORD} networks: - default ports: - "6379:6379" restart: unless-stopped
পরিষেবাগুলির সাথে ডকার-কম্পোজ ফাইল
দ্রুত সংযোগের জন্য আমরা ডকারে দুটি পরিষেবা চালু করতে যাচ্ছি। ডাটাবেস বা রেডিসে দ্রুত অ্যাক্সেসের সুবিধার্থে আমি এই প্রক্রিয়াটিকে সুগম করেছি, আমাদের দক্ষতার সাথে ডেটা পুনরুদ্ধার করার অনুমতি দেয়। সুতরাং, আসুন সেই পরিষেবাগুলি চালাই docker-compose up
, এবং আমাদের docker ps
নিম্নলিখিত আউটপুটের পরে আউটপুট দেখতে সক্ষম হতে হবে:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES e4bef95de1dd postgres:latest "docker-entrypoint.s…" About a minute ago Up About a minute 0.0.0.0:5432->5432/tcp postgres 365e3a68351a redis:latest "docker-entrypoint.s…" About a minute ago Up About a minute 0.0.0.0:6379->6379/tcp redis
এখন, আমাদের src/@types/index.ts
ফাইলটি তৈরি করতে হবে যেখানে আমরা অ্যাপ্লিকেশনের জন্য আমাদের প্রকারগুলি সংরক্ষণ করি:
export enum Role { Admin = 'admin', Blogger = 'blogger', } export type UserSession = { id: number; }; export type DatabaseDate = { created_at: Date; updated_at: Date; }; export type DefaultUserData = { role: Role; }; export interface User extends DatabaseDate { id: number; email: string; username: string; password: string; role: Role; }
সেবা জন্য প্রকার
এই মুহুর্তে, সংযোগ, স্থানান্তর এবং বীজের জন্য আপনার প্রকল্পের রুট এবং ডাটাবেস ফোল্ডারে knexfile.ts
থাকতে হবে।
আমি পোস্টগ্রেসের সাথে একটি Node.js সার্ভার তৈরি করার একটি বিশদ ব্যাখ্যা রেখেছি এবং কীভাবে ব্যবহারকারীদেরকে ডাটাবেসে স্থানান্তর করতে হবে এবং যেখানে আমরা সেই env ভেরিয়েবলগুলি ব্যবহার করছি সে সম্পর্কে এক্সপ্রেস নিবন্ধে Knex-এ একটি বিশদ ব্যাখ্যা রেখেছি।
আমরা একই পৃষ্ঠায় আছি তা নিশ্চিত করতে আমি বিশেষভাবে মাইগ্রেশন পরীক্ষা করতে চাই। আমরা ইতিমধ্যে আমাদের পরিষেবাগুলি চালু করেছি, এবং আমাদের ডাটাবেসের সংযোগ পরীক্ষা করতে সক্ষম হতে হবে৷
docker exec -it postgres psql -U username_123 user_flow_boilerplate
সংযোগটি ভাল হলে, আপনি psql
কনসোলে থাকবেন। ঠিক আছে, যদি সংযোগে কোন সমস্যা না থাকে, তাহলে আমাদের টেবিলগুলি সেখানে স্থানান্তর করতে সক্ষম হওয়া উচিত। knex migrate:latest
। তারপর আপনার ডাটাবেসের মধ্যে আপনার users
টেবিলে নতুন যোগ করা কলামগুলি পর্যবেক্ষণ করা উচিত।
আসুন এটিকে জাল ডেটা দিয়ে knex seed:run
করি
সুতরাং, আমরা এখন ডাটাবেস ম্যানিপুলেট করার জন্য সজ্জিত, আমাদের প্রয়োজন অনুসারে ব্যবহারকারীদের যোগ, মুছে বা আপডেট করার অনুমতি দেয়।
অবশেষে, আমরা সেটিংস এবং প্রস্তুতি সম্পর্কে ভুলে যেতে পারি এবং বিশেষভাবে ব্যবহারকারীর প্রবাহের উপর ফোকাস করতে পারি। এর জন্য, আমাদের একটি রাউটার তৈরি করতে হবে। আমাদের সেই রাউটার দ্বারা নিম্নলিখিত ক্রিয়াকলাপগুলি পরিচালনা করতে হবে: login
, logout
, signup
, delete_user
, update_user
।
এর জন্য, src/routes/index.ts
এ, নিম্নলিখিত কোডটি যোগ করুন:
import { Router } from 'express'; import { authRouter } from 'src/routes/authRouter'; import { healthController } from 'src/controllers/healthController'; import { sessionController } from 'src/controllers/sessionController'; import { authMiddleware } from 'src/middlewares/authMiddleware'; import { userRouter } from 'src/routes/userRouter'; export const router = Router({ mergeParams: true }); router.get('/health', healthController); router.use('/auth', authRouter); router.get('/session', authMiddleware, sessionController); router.use('/user', authMiddleware, userRouter); router.use((_, res) => { return res.status(404).json({ message: 'Not Found' }); });
রুট ফাইল
আপনি দেখতে পাচ্ছেন, শুরুতে, আমরা /health
রুট যোগ করেছি যা আমরা ইতিমধ্যে পরীক্ষা করেছি। তাহলে, আসুন সেখানে সেই রুটগুলি প্রয়োগ করতে এন্ট্রি পয়েন্টটি আপডেট করি। প্রথমত, আগের get
মুছে ফেলুন।
-> REMOVE -> app.get('/api/v1/health', (req, res) => res.status(200).json({ message: 'OK' }));
এবং ফাইলের শীর্ষে যোগ করুন:
import { router } from 'src/routes'; // ... app.use(cors()); app.use('/api/v1', router);
এবং কোড সহ src/controllers/healthController.ts
health
পরীক্ষার জন্য প্রথম নিয়ামক তৈরি করুন:
import { Request, Response } from 'express'; export const healthController = (_: Request, res: Response) => res.status(200).send('ok');
স্বাস্থ্য নিয়ন্ত্রক
এখন, রাউটারে ফিরে আসা যাক, এবং রুটগুলিতে আমাদের আরও কী যুক্ত করতে হবে তা পরীক্ষা করা যাক। আমাদের আরও দুটি ফাইল যোগ করতে হবে: authRouter.ts
এবং userRouter.ts
import { Router } from 'express'; import { signUpController } from 'src/controllers/auth/signUpController'; import { loginController } from 'src/controllers/auth/loginController'; export const authRouter = Router(); authRouter.post('/signup', signUpController); authRouter.post('/login', loginController);
প্রমাণ রাউটার
import { Router } from 'express'; import { updateUserController } from 'src/controllers/user/updateUserController'; import { deleteUserController } from 'src/controllers/user/deleteUserController'; import { logoutController } from 'src/controllers/user/logoutController'; import { updatePasswordController } from 'src/controllers/user/updatePasswordController'; export const userRouter = Router(); userRouter.patch('/', updateUserController); userRouter.delete('/', deleteUserController); userRouter.post('/logout', logoutController); userRouter.post('/update-password', updatePasswordController);
ব্যবহারকারী রাউটার
আমি পঠনযোগ্যতা এবং বিচ্ছিন্ন কার্যকারিতা বজায় রাখার দায়িত্বের জন্য এই যুক্তিটিকে ভাগ করেছি। সেই সমস্ত রুটের কন্ট্রোলারের প্রয়োজন যেখানে আমরা লজিক পরিচালনা করতে যাচ্ছি।
প্রমাণীকরণ এবং স্বাস্থ্য রুটগুলির প্রমাণীকরণ মিডলওয়্যারের প্রয়োজন নেই, তাই সেই রুটগুলি সুরক্ষিত নয়, তবে যদি কোনও মিল না থাকে তবে আমরা একটি স্থিতি 404 পেতে যাচ্ছি।
router.get('/health', healthController); router.use('/auth', authRouter);
এখন, যেহেতু আমরা সমস্ত রুট সেট আপ করেছি, আমাদের ব্যবহারকারী মডেল সেট করতে হবে।
আমি ব্যবহারকারী মডেলের জন্য একটি বেস মডেল ব্যবহার করব, যেখান থেকে আমি CRUD পদ্ধতিগুলি পুনরায় ব্যবহার করব। যদিও আমি পূর্বে অন্য একটি মডেল তৈরি কভার করেছিsrc/models/Model.ts
এ তৈরি করুন
import { database } from 'root/database'; export abstract class Model { protected static tableName?: string; protected static get table() { if (!this.tableName) { throw new Error('The table name must be defined for the model.'); } return database(this.tableName); } public static async insert<Payload>(data: Payload): Promise<{ id: number; }> { const [result] = await this.table.insert(data).returning('id'); return result; } public static async updateOneById<Payload>( id: number, data: Payload ): Promise<{ id: number; }> { const [result] = await this.table.where({ id }).update(data).returning('id'); return result; } public static async delete(id: number): Promise<number> { return this.table.where({ id }).del(); } public static async findOneById<Result>(id: number): Promise<Result> { return this.table.where('id', id).first(); } public static async findOneBy<Payload, Result>(data: Payload): Promise<Result> { return this.table.where(data as string).first(); } }
বেস মডেল
বেস মডেলের সাথে, আমাদের একই ফোল্ডারে UserModel.ts
তৈরি করতে সক্ষম হতে হবে:
import { Model } from 'src/models/Model'; import { Role, User, DefaultUserData } from 'src/@types'; export class UserModel extends Model { static tableName = 'users'; public static async create<Payload>(data: Payload) { return super.insert<Payload & DefaultUserData>({ ...data, role: data.role || Role.Blogger, }); } public static findByEmail(email: string): Promise<User | null> { return this.findOneBy< { email: string; }, User >({ email }); } public static findByUsername(username: string): Promise<User | null> { return this.findOneBy< { username: string; }, User >({ username }); } }
ব্যবহারকারী মডেল
ব্যবহারকারীর মডেলে, পেলোড থেকে প্রদান না করলে আমি ডিফল্টরূপে role
সেট করি। এবং এখন যেহেতু আমাদের মডেলগুলি প্রস্তুত আছে, আমরা সেগুলিকে আমাদের কন্ট্রোলার এবং মিডলওয়্যারের মধ্যে ব্যবহার করতে এগিয়ে যেতে পারি।
একটি Node.js অ্যাপ্লিকেশনের auth Middleware আগত অনুরোধগুলি প্রমাণীকরণের জন্য দায়ী, নিশ্চিত করে যে তারা বৈধ এবং অনুমোদিত ব্যবহারকারীদের কাছ থেকে আসছে।
এটি সাধারণত আগত অনুরোধগুলিকে বাধা দেয়, প্রমাণীকরণ টোকেন বা শংসাপত্রগুলি বের করে এবং এই ক্ষেত্রে JWT (JSON ওয়েব টোকেন) এর মতো পূর্বনির্ধারিত প্রমাণীকরণ প্রক্রিয়ার বিরুদ্ধে তাদের বৈধতা যাচাই করে।
যদি প্রমাণীকরণ প্রক্রিয়া সফল হয়, মিডলওয়্যার অনুরোধটিকে অনুরোধ-প্রতিক্রিয়া চক্রের পরবর্তী হ্যান্ডলারের কাছে যেতে দেয়। যাইহোক, যদি প্রমাণীকরণ ব্যর্থ হয়, এটি একটি উপযুক্ত HTTP স্ট্যাটাস কোড (যেমন, 401 অননুমোদিত) দিয়ে সাড়া দেয় এবং ঐচ্ছিকভাবে একটি ত্রুটি বার্তা প্রদান করে।
src/middlewares
ফোল্ডার তৈরি করুন এবং নিম্নলিখিত কোড সহ একটি ফাইল authMiddleware.ts
যোগ করুন:
import { jwt } from 'src/utils/jwt'; import { Redis } from 'src/redis'; import type { Request, Response, NextFunction } from 'express'; import type { UserSession } from 'src/@types'; export async function authMiddleware(req: Request, res: Response, next: NextFunction) { const authHeader = req.headers['authorization']; const token = authHeader && authHeader.split(' ')[1]; const JWT_SECRET = process.env.JWT_SECRET; if (!token) return res.sendStatus(401); if (!JWT_SECRET) { console.error('JWT_SECRET Not Found'); return res.sendStatus(500); } if (!token) return res.status(401).json({ error: 'Token not provided' }); try { const userSession = await jwt.verify<UserSession>(token); if (!userSession) { return res.sendStatus(401); } const storedToken = await Redis.getSession(userSession.id); if (!storedToken || storedToken !== token) { return res.sendStatus(401); } req.user = userSession; next(); } catch (error) { console.error('JWT_ERROR', error); return res.sendStatus(401); } }
Auth মিডলওয়্যার ফাইল
auth মিডলওয়্যার অনুরোধের শিরোনাম থেকে JWT টোকেন বের করে, JWT লাইব্রেরি ব্যবহার করে এর বৈধতা যাচাই করে এবং Redis-এ সংরক্ষিত টোকেনের সাথে মেলে কিনা তা পরীক্ষা করে।
যদি টোকেনটি বৈধ হয় এবং সঞ্চিত টোকেনের সাথে মেলে, মিডলওয়্যার অনুরোধ বস্তু ( req.user
) এ প্রমাণীকৃত ব্যবহারকারী সেশন সেট করে এবং পরবর্তী মিডলওয়্যার বা রুট হ্যান্ডলারের কাছে নিয়ন্ত্রণ পাস করার জন্য next()
ফাংশনটি কল করে। অন্যথায়, এটি একটি 401 স্ট্যাটাস কোড দিয়ে সাড়া দেয় যা প্রমাণীকরণ ব্যর্থতা নির্দেশ করে।
আসুন jwt এর জন্য ব্যবহার পর্যালোচনা করি। নিম্নলিখিত কোড সহ src/utils/jwt.ts
ফাইল তৈরি করুন:
require('dotenv').config(); import jsonwebtoken from 'jsonwebtoken'; const JWT_SECRET = process.env.JWT_SECRET as string; export const jwt = { verify: <Result>(token: string): Promise<Result> => { if (!JWT_SECRET) { throw new Error('JWT_SECRET not found in environment variables!'); } return new Promise((resolve, reject) => { jsonwebtoken.verify(token, JWT_SECRET, (error, decoded) => { if (error) { reject(error); } else { resolve(decoded as Result); } }); }); }, sign: (payload: string | object | Buffer): Promise<string> => { if (!JWT_SECRET) { throw new Error('JWT_SECRET not found in environment variables!'); } return new Promise((resolve, reject) => { try { resolve(jsonwebtoken.sign(payload, JWT_SECRET)); } catch (error) { reject(error); } }); }, };
JWT ইউটিলিটি ফাইল
এই ইউটিলিটি Node.js অ্যাপ্লিকেশনের মধ্যে JSON ওয়েব টোকেন পরিচালনার ক্ষেত্রে একটি গুরুত্বপূর্ণ ভূমিকা পালন করে। jwt
অবজেক্ট jsonwebtoken
লাইব্রেরি ব্যবহার করে, JWTs স্বাক্ষর এবং যাচাইকরণ উভয়ের জন্য ফাংশন রপ্তানি করে। এই ফাংশনগুলি জেডব্লিউটি তৈরি এবং যাচাইকরণের সুবিধা দেয়, যা অ্যাপ্লিকেশনে প্রমাণীকরণ প্রক্রিয়া বাস্তবায়নের জন্য অপরিহার্য।
পরিবেশ পরিবর্তনশীল ব্যবস্থাপনার জন্য সর্বোত্তম অনুশীলনগুলি মেনে চলার সময় ইউটিলিটি, Node.js অ্যাপ্লিকেশনের মধ্যে নিরাপদ প্রমাণীকরণ প্রক্রিয়া নিশ্চিত করে JWTs পরিচালনার কার্যকারিতাকে অন্তর্ভুক্ত করে।
ডাটাবেস, ক্যাশে এবং বার্তা ব্রোকার হিসাবে ব্যবহৃত হয়। ক্যাশিং, সেশন ম্যানেজমেন্ট, রিয়েল-টাইম অ্যানালিটিক্স, মেসেজিং সারি, লিডারবোর্ড এবং আরও অনেক কিছু সহ বিভিন্ন ব্যবহারের ক্ষেত্রে সাধারণত ব্যবহৃত হয়।
Redis থেকে টোকেন চেক করা JWT টোকেনের জন্য নিরাপত্তা এবং বৈধতার একটি অতিরিক্ত স্তর হিসাবে কাজ করে। এর সেটিংসে ডুব দেওয়া যাক। এর জন্য, নিম্নলিখিত কোড সহ src/redis/index.ts
ফাইল তৈরি করুন:
require('dotenv').config({ path: '../../.env', }); import process from 'process'; import * as redis from 'redis'; const client = redis.createClient({ url: `redis://:${process.env.REDIS_PASSWORD}@${process.env.REDIS_HOST}:${process.env.REDIS_PORT}`, }); client.on('error', error => console.error('Redis Client Error', error)); const connect = async () => { try { await client.connect(); console.log('Connected to Redis'); } catch (err) { console.error(`Could not connect to Redis: ${err}`); process.exit(1); } }; class Redis { public static setSession(userId: number, token: string) { if (!userId) throw new Error('userId is required'); if (!token) throw new Error('token is required'); try { return client.set(`session:${userId}`, token); } catch (error) { console.error(error); } } public static getSession(userId: number) { if (!userId) throw new Error('userId is required'); return client.get(`session:${userId}`); } public static deleteSession(userId: string) { if (!userId) throw new Error('userId is required'); try { return client.del(`session:${userId}`); } catch (error) { console.error(error); } } } export { client, connect, Redis };
রিডিস সেশন স্টোর
Redis দ্বারা, আমরা ব্যবহারকারীর সেশন টোকেন সংরক্ষণ এবং পরিচালনা করতে যাচ্ছি। অথ মিডলওয়্যারে, JWT টোকেনের সত্যতা যাচাই করার পরে, মিডলওয়্যার টোকেনটি বিদ্যমান কিনা এবং সংশ্লিষ্ট ব্যবহারকারীর সেশনের জন্য Redis-এ সংরক্ষিত একটির সাথে মেলে কিনা তা পরীক্ষা করে। এটি নিশ্চিত করতে সাহায্য করে যে শুধুমাত্র বৈধ এবং অনুমোদিত ব্যবহারকারীরা সুরক্ষিত রুটগুলি অ্যাক্সেস করতে পারে৷
রেডিস ব্যবহারকারীর সেশন টোকেন বজায় রাখার জন্য একটি মূল-মূল্যের দোকান হিসাবে ব্যবহৃত হয়। যখন একজন ব্যবহারকারী লগ ইন করেন বা প্রমাণীকরণ করেন, তখন তাদের সেশন টোকেন রেডিসে সংরক্ষণ করা হয়। এটি পরবর্তী প্রমাণীকরণ চেকের সময় সেশন টোকেনগুলির দক্ষ এবং দ্রুত পুনরুদ্ধারের অনুমতি দেয়।
Redis দক্ষ সেশন পরিচালনার জন্য অথ মিডলওয়্যারে ব্যবহার করা হয়, যখন Redis-সম্পর্কিত ফাইলটি Redis সার্ভারের সাথে কনফিগারেশন এবং সংযোগ পরিচালনা করে এবং অ্যাপ্লিকেশনের অন্যান্য অংশে Redis-এর সাথে ইন্টারঅ্যাক্ট করার জন্য ফাংশন প্রদান করে।
এই সেটআপটি নিরাপদ এবং নির্ভরযোগ্য প্রমাণীকরণ প্রক্রিয়া নিশ্চিত করে, ব্যবহারকারী সেশন টোকেনগুলি Redis-এ সংরক্ষিত এবং পরিচালিত হয়।
শেষ অংশটি হল আমাদের এন্ট্রি পয়েন্টে রেডিসের সাথে সংযোগ করতে হবে:
// all imports import * as Redis from 'src/redis'; const app = express(); const PORT = process.env.PORT || 9999; // middlewares (async () => { try { await Redis.connect(); app.listen(PORT, async () => { console.log(`Server is running on port ${PORT}`); }); } catch (error) { console.error('Failed to start server:', error); process.exit(1); } })();
Redis এর সাথে সংযোগ করুন
প্রমাণীকরণ প্রস্তুতি সম্পন্ন করার পর, আমরা এখন আমাদের ফোকাস কন্ট্রোলারের দিকে সরাতে পারি।
রুটের কন্ট্রোলাররা উদ্বেগকে আলাদা করে এবং কোড রক্ষণাবেক্ষণের প্রচার করে অ্যাপ্লিকেশনের যুক্তি সংগঠিত করতে সাহায্য করে। আমরা ইতিমধ্যে স্বাস্থ্য পরীক্ষার জন্য নিয়ামক তৈরি করেছি। পরবর্তী, আমরা ব্যবহারকারীর সাথে ক্রিয়াকলাপ পরিচালনা করার জন্য কন্ট্রোলার তৈরি করতে এগিয়ে যাব।
আমরা যে প্রথম নিয়ামকটি নিতে যাচ্ছি তা হল sessionController.ts
যা নিম্নলিখিত কোড সহ src/controllers
এ থাকতে হবে:
import { Request, Response } from 'express'; import { UserModel } from 'src/models/UserModel'; import type { User } from 'src/@types'; export const sessionController = async (req: Request, res: Response) => { if (!req.user) return res.sendStatus(401); try { const user = await UserModel.findOneById<User>(req.user.id); if (user) { return res.status(200).json(user); } else { return res.sendStatus(401); } } catch (error) { return res.sendStatus(500); } };
সেশন কন্ট্রোলার
এই কন্ট্রোলারটি একটি সেশন-সম্পর্কিত এন্ডপয়েন্ট পরিচালনা করার উদ্দেশ্যে কাজ করে, সম্ভবত বর্তমানে প্রমাণীকৃত ব্যবহারকারী সম্পর্কে তথ্য পুনরুদ্ধারের জন্য দায়ী। নিম্নলিখিত কারণে আমাদের এই নিয়ামক প্রয়োজন:
ব্যবহারকারীর সেশনের তথ্য: এই নিয়ামকটি অ্যাপ্লিকেশনটিকে ব্যবহারকারীর সেশন সম্পর্কে তথ্য পুনরুদ্ধার করার অনুমতি দেয়, যেমন তাদের ব্যবহারকারীর প্রোফাইল বা অন্যান্য প্রাসঙ্গিক ডেটা। এই তথ্য ব্যবহারকারীর অভিজ্ঞতা কাস্টমাইজ করতে বা ব্যবহারকারীর প্রোফাইলের উপর ভিত্তি করে ব্যক্তিগতকৃত সামগ্রী প্রদানের জন্য উপযোগী হতে পারে।
প্রমাণীকরণ এবং অনুমোদন: req.user
বিদ্যমান কিনা তা পরীক্ষা করে, নিয়ন্ত্রক নিশ্চিত করে যে শুধুমাত্র প্রমাণীকৃত ব্যবহারকারীরা এন্ডপয়েন্ট অ্যাক্সেস করতে পারে। এটি প্রমাণীকরণ এবং অনুমোদনের নিয়মগুলি প্রয়োগ করতে সাহায্য করে, এটি নিশ্চিত করে যে সংবেদনশীল ব্যবহারকারীর ডেটা শুধুমাত্র অনুমোদিত ব্যবহারকারীদের কাছে অ্যাক্সেসযোগ্য।
ব্যবহারকারীর প্রোফাইল পুনরুদ্ধার: নিয়ামক তাদের সেশন আইডির উপর ভিত্তি করে ব্যবহারকারীর তথ্য পুনরুদ্ধার করতে ডাটাবেস ( UserModel
ব্যবহার করে) জিজ্ঞাসা করে। এটি অ্যাপ্লিকেশনটিকে গতিশীলভাবে ব্যবহারকারী-নির্দিষ্ট ডেটা আনার অনুমতি দেয়, প্রতিটি ব্যবহারকারীর জন্য একটি উপযোগী অভিজ্ঞতা প্রদান করে। এই অংশটি অবশ্যই Redis ক্যাশে দ্বারা উন্নত করা যেতে পারে:
import { Request, Response } from 'express'; import { UserModel } from 'src/models/UserModel'; import { Redis } from 'src/redis'; import type { User } from 'src/@types'; export const sessionController = async (req: Request, res: Response) => { if (!req.user) return res.sendStatus(401); try { const cachedProfile = await Redis.getSession(req.user.id); if (cachedProfile) { return res.status(200).json(JSON.parse(cachedProfile)); } else { const user = await UserModel.findOneById<User>(req.user.id); if (user) { await Redis.setSession(req.user.id, JSON.stringify(user), CACHE_EXPIRATION); return res.status(200).json(user); } else { return res.sendStatus(401); } } } catch (error) { console.error('Error retrieving user profile:', error); return res.sendStatus(500); } };
Redis সেট সেশন সহ সেশন কন্ট্রোলার ফাইল
সেকেন্ডের মধ্যে ক্যাশের মেয়াদ শেষ হওয়ার সময় নির্দিষ্ট করতে আমরা একটি ধ্রুবক CACHE_EXPIRATION
সংজ্ঞায়িত করি। এই উদাহরণে, এটি 3600 সেকেন্ড (1 ঘন্টা) সেট করা হয়েছে। ক্যাশে করা ডেটা পর্যায়ক্রমে রিফ্রেশ করা হয়, ব্যবহারকারীদের কাছে পুরানো ডেটা সরবরাহ করা থেকে বাধা দেয় এবং ক্যাশে ডেটার অখণ্ডতা বজায় রাখে।
signUpController
তৈরি করতে এগিয়ে যাওয়ার আগে, যা আমাদের অ্যাপ্লিকেশনে নতুন ব্যবহারকারীদের জন্য সাইন-আপ প্রক্রিয়া পরিচালনা করে, আসুন স্কিমাটি পর্যালোচনা করি:
আমাদের ক্ষেত্রে, ডাটাবেস ইমেলে বিদ্যমান একটি দিয়ে সাইন আপ করার চেষ্টা করার সময়, আমরা ব্যবহারকারীর অস্তিত্ব আছে কিনা তা স্পষ্টভাবে প্রকাশ না করে ব্যবহারকারীর গোপনীয়তাকে অগ্রাধিকার দিই। পরিবর্তে, আমরা Invalid email or password
উল্লেখ করে একটি জেনেরিক বার্তা দিয়ে ক্লায়েন্টকে অবহিত করি।
এই পদ্ধতিটি ক্লায়েন্টকে বিদ্যমান ব্যবহারকারীদের সম্পর্কে অপ্রয়োজনীয় তথ্য প্রকাশ না করে বৈধ শংসাপত্র জমা দিতে উত্সাহিত করে।
এখন আসুন src/controllers/auth/signUpController.ts
তৈরি করি এবং নিম্নলিখিত কোডটি যোগ করি:
import bcrypt from 'bcrypt'; import { jwt } from 'src/utils/jwt'; import { Request, Response } from 'express'; import { validate } from 'src/helpers/validation/validate'; import { userSchema } from 'src/helpers/validation/schemas/userSchema'; import { UserModel } from 'src/models/UserModel'; import { Redis } from 'src/redis'; import type { User } from 'src/@types'; import { getRandomString } from 'src/utils/getRandomString'; type Payload = Omit<User, 'id' | 'created_at' | 'updated_at' | 'role'>; export async function signUpController(req: Request, res: Response) { const { email, password }: Payload = req.body; const validation = validate<Payload>(req.body, userSchema); if (!validation.isValid) { return res.status(400).send(`Invalid ${validation.invalidKey}`); } try { const user = await UserModel.findOneBy({ email }); if (user) { return res.status(400).json({ message: 'Invalid email or password' }); } const hashedPassword = (await bcrypt.hash(password, 10)) as string; const username = `${email.split('@')[0]}${getRandomString(5)}`; const createdUser = await UserModel.create<Payload>({ email, password: hashedPassword, username, }); const token = await jwt.sign({ id: createdUser.id, }); await Redis.setSession(createdUser.id, token); res.status(200).json({ token, }); } catch (error) { return res.sendStatus(500); } }
সাইন আপ কন্ট্রোলার
নিয়ামক ব্যবহারকারীর ইমেল এবং পাসওয়ার্ড সম্বলিত একটি অনুরোধ গ্রহণ করে, সাধারণত একটি সাইন-আপ ফর্ম থেকে৷ এটি প্রয়োজনীয় বিন্যাস পূরণ করে তা নিশ্চিত করতে পূর্বনির্ধারিত userSchema
বিরুদ্ধে আগত ডেটা যাচাই করে।
যদি বৈধতা সফলভাবে পাস হয়, কোন বিদ্যমান ব্যবহারকারী এবং বৈধ ক্ষেত্র নির্দেশ করে, নিয়ামক bcrypt.hash
ব্যবহার করে পাসওয়ার্ড হ্যাশ করতে এগিয়ে যায়, একটি username
তৈরি করে, এবং UserModel.create
ব্যবহার করে ব্যবহারকারী তৈরি করে।
অবশেষে, এটি jwt
ব্যবহার করে একটি token
তৈরি করে, Redis
এ session
ডেটা সেট করে এবং ব্যবহারকারীকে token
ফেরত পাঠায়।
এখন, একটি লগইন কন্ট্রোলার তৈরিতে ফোকাস করা যাক। src/controllers/auth/loginController.ts
ফাইল তৈরি করুন :
require('dotenv').config({ path: '../../.env', }); import bcrypt from 'bcrypt'; import { Request, Response } from 'express'; import { jwt } from 'src/utils/jwt'; import { UserModel } from 'src/models/UserModel'; import { Redis } from 'src/redis'; export async function loginController(req: Request, res: Response) { const { email, password } = req.body; if (!email || !password) { return res.status(400).json({ message: 'Invalid email or password' }); } try { const user = await UserModel.findByEmail(email); if (user) { const isValidPassword = await bcrypt.compare(password, user.password); if (!isValidPassword) { return res.status(400).json({ message: 'Invalid email or password' }); } const token: string = await jwt.sign({ id: user.id, }); await Redis.setSession(user.id, token); res.status(200).json({ token }); } else { return res.status(400).json({ message: 'Invalid email or password' }); } } catch (error) { console.error(error); return res.sendStatus(500); } }
লগইন কন্ট্রোলার
মূলত, আমরা প্রদত্ত ক্ষেত্রগুলিকে যাচাই করে এবং তারপর ব্যবহারকারীর অস্তিত্ব পরীক্ষা করে শুরু করি। যদি কোনো ব্যবহারকারী খুঁজে না পাওয়া যায়, আমরা signupController
আচরণের মতো Invalid email or password
বার্তা সহ একটি 400 স্ট্যাটাস কোড দিয়ে প্রতিক্রিয়া জানাই।
যদি কোনো ব্যবহারকারী থাকে, আমরা bcrypt.compare
ব্যবহার করে ডাটাবেসে সংরক্ষিত হ্যাশ করা পাসওয়ার্ডের সাথে প্রদত্ত পাসওয়ার্ডের তুলনা করতে এগিয়ে যাই।
যদি পাসওয়ার্ড মেলে না, আমরা পরিচিত বার্তা 'অবৈধ ইমেল বা পাসওয়ার্ড' দিয়ে প্রতিক্রিয়া জানাই। অবশেষে, সফল প্রমাণীকরণের পরে, আমরা একটি টোকেন তৈরি করি, সেশনটি Redis-এ সেট করি এবং টোকেনটি ক্লায়েন্টের কাছে ফেরত পাঠাই।
আসুন আমাদের সুরক্ষিত কন্ট্রোলারগুলি পর্যালোচনা করি, যা মিডলওয়্যার থেকে প্রাপ্ত একটি user_id উপস্থিতির উপর নির্ভর করে। এই কন্ট্রোলারগুলির মধ্যে কাজ করার জন্য আমরা ধারাবাহিকভাবে এই user_id-এর উপর নির্ভর করি। যে ক্ষেত্রে অনুরোধে authorization
শিরোনাম নেই, আমাদের অবশ্যই একটি 401
স্ট্যাটাস কোড দিয়ে প্রতিক্রিয়া জানাতে হবে।
const authHeader = req.headers['authorization'];
নিম্নলিখিত কোড দিয়ে src/controllers/user/logoutController.ts
ফাইল তৈরি করুন:
import type { Request, Response } from 'express'; import { Redis } from 'src/redis'; export async function logoutController(req: Request, res: Response) { try { await Redis.deleteSession(req.user.id); return res.sendStatus(200); } catch (error) { return res.sendStatus(500); } }
লগআউট কন্ট্রোলার
এই logoutController
, সিস্টেম থেকে একজন ব্যবহারকারীকে লগ আউট করার জন্য দায়ী। একটি অনুরোধ পাওয়ার পরে, এটি user.id
এর সাথে যুক্ত সেশনটি মুছে ফেলার জন্য Redis ক্লায়েন্টের সাথে যোগাযোগ করে। অপারেশন সফল হলে, এটি সফল লগআউট নির্দেশ করার জন্য একটি 200
স্ট্যাটাস কোড দিয়ে সাড়া দেয়।
যাইহোক, প্রক্রিয়া চলাকালীন একটি ত্রুটি দেখা দিলে, এটি একটি অভ্যন্তরীণ সার্ভার ত্রুটি সংকেত দিতে 500
স্ট্যাটাস কোড দিয়ে প্রতিক্রিয়া জানায়।
এর পরে, আসুন ব্যবহারকারীর ডেটা মুছে ফেলার বিষয়ে আলোচনা করা যাক।
src/controllers/user/deleteUserController.ts
তৈরি করুন এবং এই কোড যোগ করুন:
import { Request, Response } from 'express'; import { UserModel } from 'src/models/UserModel'; import { Redis } from 'src/redis'; export const deleteUserController = async (req: Request, res: Response) => { const user_id = req.user.id; try { await Redis.deleteSession(user_id); await UserModel.delete(user_id); return res.sendStatus(200); } catch (error) { return res.sendStatus(500); } };
ব্যবহারকারী নিয়ামক মুছুন
যখন একটি অনুরোধ গৃহীত হয়, এটি অনুরোধ বস্তু থেকে ব্যবহারকারী আইডি বের করে, সাধারণত প্রমাণীকরণ মিডলওয়্যার থেকে প্রাপ্ত হয়।
পরবর্তীকালে, এটি Redis ক্লায়েন্ট ব্যবহার করে Redis থেকে এই user_id
সাথে যুক্ত সেশন মুছে ফেলার জন্য এগিয়ে যায়। পরবর্তীতে, এটি ডাটাবেস থেকে ব্যবহারকারীর ডেটা মুছে ফেলার জন্য UserModel
এর delete
পদ্ধতি চালু করে।
সেশন এবং ব্যবহারকারীর ডেটা উভয়ই সফলভাবে মুছে ফেলার পরে, এটি সফল মোছা নির্দেশ করার জন্য 200
স্ট্যাটাস কোডের সাথে প্রতিক্রিয়া জানায়। মুছে ফেলার প্রক্রিয়া চলাকালীন একটি ত্রুটি ঘটলে, এটি একটি অভ্যন্তরীণ সার্ভার ত্রুটি বোঝাতে 500
স্ট্যাটাস কোড দিয়ে প্রতিক্রিয়া জানায়।
সিস্টেমে ব্যবহারকারীর ডেটা আপডেট করতে src/controllers/user/updateUserController.ts
তৈরি করুন এবং ফাইলটিতে নিম্নলিখিত কোড যোগ করুন:
import { Request, Response } from 'express'; import { UserModel } from 'src/models/UserModel'; import { filterObject } from 'src/utils/filterObject'; type Payload = { first_name?: string; last_name?: string; username?: string; }; export const updateUserController = async (req: Request, res: Response) => { const { first_name, last_name, username } = req.body; const payload: Payload = filterObject({ first_name, last_name, username, }); try { const existingUserName = await UserModel.findByUsername(username); if (existingUserName) { return res.status(400).json({ error: 'Invalid username', }); } const updatedUser = await UserModel.updateOneById<typeof payload>(req.user.id, payload); res.status(200).json(updatedUser); } catch (error) { res.sendStatus(500); } };
ব্যবহারকারী কন্ট্রোলার আপডেট করুন
একটি অনুরোধ পাওয়ার পরে, এটি অনুরোধের বডি থেকে first_name
, last_name
, এবং username
ক্ষেত্রগুলি বের করে। এর পরে, এটি filterObject
ইউটিলিটি ফাংশন ব্যবহার করে এই ক্ষেত্রগুলিকে ফিল্টার করে তা নিশ্চিত করতে যে শুধুমাত্র বৈধ ক্ষেত্রগুলি পেলোডে অন্তর্ভুক্ত করা হয়েছে।
পরবর্তীকালে, এটি পরীক্ষা করে যে প্রদত্ত username
ডাটাবেসে ইতিমধ্যেই বিদ্যমান আছে কিনা। যদি এটি হয়, নিয়ামক একটি 400
স্ট্যাটাস কোড এবং একটি ভুল username
নির্দেশ করে একটি ত্রুটি বার্তা দিয়ে প্রতিক্রিয়া জানায়৷ username
অনন্য হলে, নিয়ামক UserModel
এর updateOneById
পদ্ধতি ব্যবহার করে ডাটাবেসে ব্যবহারকারীর ডেটা আপডেট করতে এগিয়ে যায়।
সফল আপডেটের পরে, এটি একটি 200
স্ট্যাটাস কোড এবং আপডেট হওয়া ব্যবহারকারীর ডেটা সহ প্রতিক্রিয়া জানায়। আপডেট প্রক্রিয়া চলাকালীন কোনো ত্রুটির ক্ষেত্রে, নিয়ামক একটি অভ্যন্তরীণ সার্ভার ত্রুটি নির্দেশ করার জন্য একটি 500
স্ট্যাটাস কোড দিয়ে প্রতিক্রিয়া জানায়।
শেষটি হবে পাসওয়ার্ড আপডেট করা, ব্যবহারকারীর ডেটা আপডেট করার মতই ধারণা, কিন্তু নতুন পাসওয়ার্ড হ্যাশ করার সাথে। আমাদের তালিকা src/controllers/user/updatePasswordController.ts
থেকে শেষ নিয়ামকটি তৈরি করুন এবং কোডটি যোগ করুন:
import { Request, Response } from 'express'; import { UserModel } from 'src/models/UserModel'; import bcrypt from 'bcrypt'; export const updatePasswordController = async (req: Request, res: Response) => { try { const { password } = req.body; if (!password) return res.sendStatus(400); const hashedPassword = (await bcrypt.hash(password, 10)) as string; const user = await UserModel.updateOneById(req.user.id, { password: hashedPassword }); return res.status(200).json({ id: user.id }); } catch (error) { return res.sendStatus(500); } };
পাসওয়ার্ড কন্ট্রোলার আপডেট করুন
একটি অনুরোধ পাওয়ার পরে, এটি অনুরোধের বডি থেকে নতুন পাসওয়ার্ড বের করে। তারপরে অনুরোধের অংশে একটি পাসওয়ার্ড দেওয়া হয়েছে কিনা তা পরীক্ষা করে। যদি না হয়, এটি একটি 400
স্ট্যাটাস কোডের সাথে প্রতিক্রিয়া জানায়, এটি একটি খারাপ অনুরোধ নির্দেশ করে। এর পরে, এটি 10 এর সল্ট ফ্যাক্টর সহ bcrypt
লাইব্রেরি ব্যবহার করে নতুন পাসওয়ার্ড হ্যাশ করে।
তারপরে হ্যাশ করা পাসওয়ার্ডটি UserModel
এর updateOneById
পদ্ধতি ব্যবহার করে ডাটাবেসে নিরাপদে সংরক্ষণ করা হয়, এটি user.id
এর সাথে সংযুক্ত করে। সফল পাসওয়ার্ড আপডেটের পরে, নিয়ামক একটি 200
স্ট্যাটাস কোড এবং ব্যবহারকারীর আইডি ধারণকারী একটি JSON অবজেক্টের সাথে প্রতিক্রিয়া জানায়।
পাসওয়ার্ড আপডেট প্রক্রিয়া চলাকালীন কোনো ত্রুটির ক্ষেত্রে, নিয়ামক অন্যান্য কন্ট্রোলারের মতো একটি অভ্যন্তরীণ সার্ভার ত্রুটি নির্দেশ করতে 500
স্ট্যাটাস কোড দিয়ে প্রতিক্রিয়া জানায়।
থেকে যাচাইকরণ সহায়ক এবং ইউটিলিটিগুলি পর্যালোচনা এবং সেট আপ করা নিশ্চিত করুন৷
আসুন সাইনআপ শেষ পয়েন্ট পরীক্ষা করা যাক:
স্পষ্ট হিসাবে, আমরা একটি টোকেন পেয়েছি, যা সেশনটি পুনরুদ্ধার করতে হেডারে ব্যবহার করা হবে।
আমরা সার্ভারে হেডারে অনুমোদনের টোকেন পাঠিয়েছি, এবং প্রতিক্রিয়া হিসাবে, সার্ভার আমাদের ডেটাবেস থেকে পুনরুদ্ধার করা ব্যবহারকারীর ডেটা সরবরাহ করেছে।
অন্বেষণ এবং নিরাপত্তা বৈশিষ্ট্য এবং Redis ক্যাশিং সঙ্গে পরীক্ষা নির্দ্বিধায়. ফাউন্ডেশনাল মডেলের জায়গায়, আপনি অতিরিক্ত কার্যকারিতা, যেমন ব্যবহারকারীদের জন্য অ্যাকাউন্ট পুনরুদ্ধার করতে পারেন যারা তাদের পাসওয়ার্ড ভুলে গেছেন। যাইহোক, এই বিষয়টি ভবিষ্যতের নিবন্ধের জন্য সংরক্ষিত থাকবে।
স্কেলযোগ্য পদ্ধতিতে রাউটিং এবং ব্যবহারকারীর প্রমাণীকরণ প্রবাহ পরিচালনা করা চ্যালেঞ্জিং হতে পারে। যদিও আমরা রুটগুলি সুরক্ষিত করার জন্য মিডলওয়্যার প্রয়োগ করেছি, পরিষেবাটির কার্যকারিতা এবং নির্ভরযোগ্যতা বাড়ানোর জন্য অতিরিক্ত কৌশলগুলি উপলব্ধ রয়েছে৷
আরও বর্ধিত ব্যবহারকারীর অভিজ্ঞতা পরিষ্কার ত্রুটি বার্তা প্রদান করে, কারণ ত্রুটি হ্যান্ডলিং একটি উল্লেখযোগ্য দিক থেকে যায় যার জন্য আরও ব্যাপক কভারেজ প্রয়োজন। যাইহোক, আমরা সফলভাবে প্রাথমিক প্রমাণীকরণ প্রবাহ বাস্তবায়ন করেছি, ব্যবহারকারীদের সাইন আপ করতে, তাদের অ্যাকাউন্টগুলি অ্যাক্সেস করতে, সেশন ডেটা পুনরুদ্ধার করতে, ব্যবহারকারীর তথ্য আপডেট করতে এবং অ্যাকাউন্টগুলি মুছতে সক্ষম করেছিলাম৷
আমি আশা করি আপনি এই যাত্রাটি অন্তর্দৃষ্টিপূর্ণ খুঁজে পেয়েছেন এবং ব্যবহারকারীর প্রমাণীকরণে মূল্যবান জ্ঞান অর্জন করেছেন।
এছাড়াও এখানে প্রকাশিত