دریابید که چگونه این فناوری ها را با یک نمایش عملی ترکیب کنید.
کنترل دسترسی مبتنی بر نقش یک مکانیسم احراز هویت امن است. می توانید از آن برای محدود کردن دسترسی به منابع خاص برای کاربرانی که نقش های خاصی دارند استفاده کنید.
این نوع احراز هویت به مدیران سیستم کمک می کند تا مجوزها را با توجه به نقش های تعیین شده کاربران کنترل کنند. این سطح از کنترل گرانول لایه ای از امنیت را اضافه می کند و به برنامه ها اجازه می دهد از دسترسی های غیرمجاز جلوگیری کنند.
پیاده سازی مکانیسم کنترل دسترسی مبتنی بر نقش با استفاده از Passport.js و JWTs
کنترل دسترسی مبتنی بر نقش (RBAC) مکانیزم محبوبی است که برای اعمال محدودیتهای دسترسی در برنامهها بر اساس نقشها و مجوزهای کاربر استفاده میشود. روش های مختلفی برای پیاده سازی مکانیسم RBAC وجود دارد.
دو رویکرد محبوب شامل استفاده از کتابخانههای اختصاصی RBAC مانند AcessControl یا استفاده از کتابخانههای احراز هویت موجود برای پیادهسازی مکانیزم است.
در این مورد، JSON Web Tokens (JWTs) راهی امن برای انتقال اعتبارنامه های احراز هویت ارائه می دهد، در حالی که Passport.js با ارائه میان افزار احراز هویت انعطاف پذیر، فرآیند احراز هویت را ساده می کند.
با استفاده از این رویکرد، می توانید نقش هایی را به کاربران اختصاص دهید و هنگام احراز هویت، آنها را در JWT رمزگذاری کنید. سپس میتوانید از JWT برای تأیید هویت و نقشهای کاربر در درخواستهای بعدی استفاده کنید، که اجازه مجوز و کنترل دسترسی مبتنی بر نقش را میدهد.
هر دو رویکرد مزایای خود را دارند و می توانند در پیاده سازی RBAC موثر باشند. انتخاب بین کدام روش برای پیاده سازی به نیازهای خاص پروژه شما بستگی دارد.
می توانید کد این پروژه را از مخزن GitHub آن دانلود کنید.
یک پروژه Express.js را راه اندازی کنید
برای شروع، یک پروژه Express.js را به صورت محلی راه اندازی کنید. هنگامی که پروژه را راه اندازی کردید، ادامه دهید و این بسته ها را نصب کنید:
npm install cors dotenv mongoose cookie-parser jsonwebtoken mongodb \
passport passport-local
سپس یک پایگاه داده MongoDB ایجاد کنید یا یک کلاستر در MongoDB Atlas راه اندازی کنید. URI اتصال پایگاه داده را کپی کنید و آن را به یک فایل .env در فهرست اصلی پروژه خود اضافه کنید:
CONNECTION_URI="connection URI"
اتصال پایگاه داده را پیکربندی کنید
در دایرکتوری ریشه، یک فایل utils/db.js جدید ایجاد کنید و کد زیر را اضافه کنید تا با استفاده از Mongoose به خوشه MongoDB در حال اجرا در Atlas متصل شوید.
const mongoose = require('mongoose');
const connectDB = async () => {
try {
await mongoose.connect(process.env.CONNECTION_URI);
console.log("Connected to MongoDB!");
} catch (error) {
console.error("Error connecting to MongoDB:", error);
}
};
module.exports = connectDB;
مدل داده را تعریف کنید
در پوشه اصلی، یک فایل model/user.model.js جدید ایجاد کنید و کد زیر را اضافه کنید تا با استفاده از Mongoose یک مدل داده برای داده های کاربران تعریف کنید.
const mongoose = require('mongoose');
const userSchema = new mongoose.Schema({
username: String,
password: String,
role: String
});
module.exports = mongoose.model('User', userSchema);
کنترلر را برای نقاط پایانی API ایجاد کنید
یک فایل controllers/user.controller.js جدید در پوشه اصلی ایجاد کنید و کد زیر را اضافه کنید.
ابتدا این واردات را انجام دهید:
const User = require('../models/user.model');
const passport = require('passport');
const { generateToken } = require('../middleware/auth');
require('../middleware/passport')(passport);
در مرحله بعد، منطق مدیریت ثبت نام کاربر و عملکرد ورود به سیستم را تعریف کنید:
exports.registerUser = async (req, res) => {
const { username, password, role } = req.body;
try {
await User.create({ username, password, role });
res.status(201).json({ message: 'User registered successfully' });
} catch (error) {
console.log(error);
res.status(500).json({ message: 'An error occurred!' });
}
};
exports.loginUser = (req, res, next) => {
passport.authenticate('local', { session: false }, (err, user, info) => {
if (err) {
console.log(err);
return res.status(500).json({
message: 'An error occurred while logging in'
});
}
if (!user) {
return res.status(401).json({
message: 'Invalid login credentials'
});
}
req.login(user, { session: false }, (err) => {
if (err) {
console.log(err);
return res.status(500).json({
message: 'An error occurred while logging in'
});
}
const { _id, username, role } = user;
const payload = { userId: _id, username, role };
const token = generateToken(payload);
res.cookie('token', token, { httpOnly: true });
return res.status(200).json({ message: 'Login successful' });
});
})(req, res, next);
};
تابع registerUser ثبت نام کاربر جدید را با استخراج نام کاربری، رمز عبور و نقش از بدنه درخواست انجام می دهد. سپس یک ورودی کاربر جدید در پایگاه داده ایجاد می کند و در صورت بروز هرگونه خطا در طول فرآیند، با یک پیام موفقیت آمیز یا یک خطا پاسخ می دهد.
از سوی دیگر، تابع loginUser ورود کاربر را با استفاده از استراتژی احراز هویت محلی ارائه شده توسط Passport.js تسهیل می کند. اعتبار کاربر را احراز هویت میکند و پس از ورود موفقیتآمیز، رمزی را برمیگرداند که سپس در یک کوکی برای درخواستهای احراز هویت بعدی ذخیره میشود. در صورت بروز هر گونه خطایی در فرآیند ورود، پیام مناسبی برمی گردد.
در نهایت، کدی را اضافه کنید که منطق واکشی اطلاعات همه کاربران از پایگاه داده را پیاده سازی می کند. ما از این نقطه پایانی به عنوان مسیر محدود استفاده خواهیم کرد تا اطمینان حاصل کنیم که فقط کاربران مجاز با نقش سرپرست می توانند به این نقطه پایانی دسترسی داشته باشند.
exports.getUsers = async (req, res) => {
try {
const users = await User.find({});
res.json(users);
} catch (error) {
console.log(error);
res.status(500).json({ message: 'An error occurred!' });
}
};
یک استراتژی احراز هویت محلی Passport.js را تنظیم کنید
برای احراز هویت کاربران پس از ارائه اعتبار ورود به سیستم، باید یک استراتژی احراز هویت محلی تنظیم کنید.
یک فایل middleware/passport.js جدید در دایرکتوری ریشه ایجاد کنید و کد زیر را اضافه کنید.
const LocalStrategy = require('passport-local').Strategy;
const User = require('../models/user.model');
module.exports = (passport) => {
passport.use(
new LocalStrategy(async (username, password, done) => {
try {
const user = await User.findOne({ username });
if (!user) {
return done(null, false);
}
if (user.password !== password) {
return done(null, false);
}
return done(null, user);
} catch (error) {
return done(error);
}
})
);
};
این کد یک استراتژی محلی passport.js را برای احراز هویت کاربران بر اساس نام کاربری و رمز عبور ارائه شده تعریف می کند.
ابتدا از پایگاه داده درخواست میکند تا کاربری با نام کاربری مشابه را پیدا کند و سپس به تأیید رمز عبور آنها میپردازد. در نتیجه، در صورت موفقیت آمیز بودن فرآیند ورود، شی کاربر احراز هویت شده را برمی گرداند.
یک میان افزار تأیید JWT ایجاد کنید
در داخل پوشه میانافزار، یک فایل auth.js جدید ایجاد کنید و کد زیر را برای تعریف میانافزاری که JWTها را تولید و تأیید میکند، اضافه کنید.
const jwt = require('jsonwebtoken');
const secretKey = process.env.SECRET_KEY;
const generateToken = (payload) => {
const token = jwt.sign(payload, secretKey, { expiresIn: '1h' });
return token;
};
const verifyToken = (requiredRole) => (req, res, next) => {
const token = req.cookies.token;
if (!token) {
return res.status(401).json({ message: 'No token provided' });
}
jwt.verify(token, secretKey, (err, decoded) => {
if (err) {
return res.status(401).json({ message: 'Invalid token' });
}
req.userId = decoded.userId;
if (decoded.role !== requiredRole) {
return res.status(403).json({
message: 'You do not have the authorization and permissions to access this resource.'
});
}
next();
});
};
module.exports = { generateToken, verifyToken };
تابع generateToken یک JWT با زمان انقضای مشخص ایجاد می کند، در حالی که تابع verifyToken بررسی می کند که آیا توکن موجود و معتبر است یا خیر. علاوه بر این، همچنین تأیید می کند که رمز رمزگشایی شده دارای نقش مورد نیاز است، اساساً، اطمینان حاصل می کند که فقط کاربران دارای نقش و مجوزهای مجاز دسترسی دارند.
برای امضای منحصربفرد JWTها، باید یک کلید مخفی منحصربفرد ایجاد کنید و آن را به فایل .env خود اضافه کنید، همانطور که در زیر نشان داده شده است.
SECRET_KEY="This is a sample secret key."
مسیرهای API را تعریف کنید
در پوشه اصلی، یک پوشه جدید ایجاد کنید و نام مسیرها را نامگذاری کنید. در داخل این پوشه یک userRoutes.js جدید ایجاد کنید و کد زیر را اضافه کنید.
const express = require('express');
const router = express.Router();
const userControllers = require('../controllers/userController');
const { verifyToken } = require('../middleware/auth');
router.post('/api/register', userControllers.registerUser);
router.post('/api/login', userControllers.loginUser);
router.get('/api/users', verifyToken('admin'), userControllers.getUsers);
module.exports = router;
این کد مسیرهای HTTP را برای REST API تعریف می کند. کاربران به طور خاص مسیریابی می کنند، سرورها به عنوان مسیر محافظت شده. با محدود کردن دسترسی به کاربران دارای نقش مدیر، به طور موثر کنترل دسترسی مبتنی بر نقش را اعمال می کنید.
فایل سرور اصلی را به روز کنید
فایل server.js خود را باز کرده و به صورت زیر به روز رسانی کنید:
const express = require('express');
const cors = require('cors');
const cookieParser = require('cookie-parser');
const app = express();
const port = 5000;
require('dotenv').config();
const connectDB = require('./utils/db');
const passport = require('passport');
require('./middleware/passport')(passport);
connectDB();
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(cors());
app.use(cookieParser());
app.use(passport.initialize());
const userRoutes = require('./routes/userRoutes');
app.use('/', userRoutes);
app.listen(port, () => {
console.log(`Server is running on port ${port}`);
});
در نهایت، سرور توسعه را برای اجرای برنامه راه اندازی کنید.
node server.js
از مکانیسم RBAC برای ارتقای سیستم های احراز هویت خود استفاده کنید
پیاده سازی کنترل دسترسی مبتنی بر نقش یک راه موثر برای افزایش امنیت برنامه های شما است.
در حالی که ترکیب کتابخانههای احراز هویت موجود برای ایجاد یک سیستم RBAC کارآمد یک رویکرد عالی است، استفاده از کتابخانههای RBAC برای تعریف صریح نقشهای کاربر و تخصیص مجوزها، راهحل قویتری را ارائه میدهد که در نهایت امنیت کلی برنامه شما را افزایش میدهد.