Découvrez comment combiner ces technologies avec une démonstration pratique.

Le contrôle d'accès basé sur les rôles est un mécanisme d'authentification sécurisé. Vous pouvez l'utiliser pour restreindre l'accès à des ressources spécifiques aux utilisateurs qui ont certains rôles.

Ce type d'authentification aide les administrateurs système à contrôler les autorisations en fonction des rôles désignés des utilisateurs. Ce niveau de contrôle granulaire ajoute une couche de sécurité, permettant aux applications d'empêcher tout accès non autorisé.

Implémentation d'un mécanisme de contrôle d'accès basé sur les rôles à l'aide de Passport.js et de JWT

Le contrôle d'accès basé sur les rôles (RBAC) est un mécanisme populaire utilisé pour appliquer les restrictions d'accès dans les applications en fonction des rôles et des autorisations des utilisateurs. Il existe différentes méthodes disponibles pour mettre en œuvre le mécanisme RBAC.

Deux approches populaires incluent l'utilisation de bibliothèques RBAC dédiées telles que

Contrôle d'accès ou en tirant parti des bibliothèques d'authentification existantes pour mettre en œuvre le mécanisme.

Dans ce cas, les jetons Web JSON (JWT) fournissent un moyen sécurisé de transmettre les identifiants d'authentification, tandis que Passport.js simplifie le processus d'authentification en fournissant une authentification flexible middleware.

En utilisant cette approche, vous pouvez attribuer des rôles aux utilisateurs et les encoder dans le JWT lorsqu'ils s'authentifient. Vous pouvez ensuite utiliser le JWT pour vérifier l'identité et les rôles de l'utilisateur dans les demandes ultérieures, ce qui permet une autorisation et un contrôle d'accès basés sur les rôles.

Les deux approches ont leurs avantages et peuvent être efficaces dans la mise en œuvre du RBAC. Le choix de la méthode à mettre en œuvre dépendra des exigences spécifiques de votre projet.

Vous pouvez télécharger le code de ce projet à partir de son Référentiel GitHub.

Configurer un projet Express.js

Pour commencer, configurer un projet Express.js localement. Une fois le projet configuré, continuez et installez ces packages :

npm installer cors dotenv mongoose cookie-parser jsonwebtoken mongodb \
passeport passeport-local

Suivant, créer une base de données MongoDB ou mettre en place un cluster sur MongoDB Atlas. Copiez l'URI de connexion à la base de données et ajoutez-le à un .env fichier dans le répertoire racine de votre projet :

CONNECTION_URI="URI de connexion"

Configurer la connexion à la base de données

Dans le répertoire racine, créez un nouveau utils/db.js et ajoutez le code ci-dessous pour établir la connexion au cluster MongoDB exécuté sur Atlas à l'aide de Mongoose.

constante mangouste = exiger('mangouste');

constante connectDB = asynchrone () => {
essayer {
attendre mongoose.connect (process.env. CONNECTION_URI );
console.enregistrer("Connecté à MongoDB !");
} attraper (erreur) {
console.erreur("Erreur de connexion à MongoDB :", erreur);
}
};

module.exports = connectDB;

Définir le modèle de données

Dans le répertoire racine, créez un nouveau modèle/utilisateur.model.js fichier et ajoutez le code suivant pour définir un modèle de données pour les données des utilisateurs à l'aide de Mongoose.

constante mangouste = exiger('mangouste');

constante userSchema = nouveau mangouste. Schéma({
nom d'utilisateur: Chaîne,
mot de passe: Chaîne,
rôle: Chaîne
});

module.exports = mangouste.model('Utilisateur', userSchema);

Créer le contrôleur pour les points de terminaison d'API

Créer un nouveau contrôleurs/user.controller.js fichier dans le répertoire racine et ajoutez le code ci-dessous.

Tout d'abord, effectuez ces importations :

constante Utilisateur = exiger('../modèles/utilisateur.modèle');
constante passeport = exiger('passeport');
constante { générer un jeton } = exiger('../middleware/auth');
exiger('../intergiciel/passeport')(passeport);

Ensuite, définissez la logique pour gérer l'enregistrement des utilisateurs et la fonctionnalité de connexion :

exports.registerUser = asynchrone (req, res) => {
constante { nom d'utilisateur, mot de passe, rôle } = req.body ;

essayer {
attendre User.create({ nom d'utilisateur, mot de passe, rôle });
res.statut(201).json({ message: 'Utilisateur enregistré avec succès' });
} attraper (erreur) {
console.log (erreur);
res.statut(500).json({ message: 'Une erreur s'est produite!' });
}
};

exports.loginUser = (req, res, suivant) => {
passeport.authenticate('local', { session: FAUX }, (err, utilisateur, info) => {
si (erre) {
console.log (erreur);

retour res.statut(500).json({
message: 'Une erreur s'est produite lors de la connexion'
});
}

si (!utilisateur) {
retour res.statut(401).json({
message: 'Authentification invalide'
});
}

req.login (utilisateur, { session: FAUX }, (erreur) => {
si (erre) {
console.log (erreur);

retour res.statut(500).json({
message: 'Une erreur s'est produite lors de la connexion'
});
}

constante { _id, nom d'utilisateur, rôle } = utilisateur ;
constante charge utile = { ID de l'utilisateur: _id, nom d'utilisateur, rôle } ;
constante jeton = generateToken (charge utile);
res.cookie('jeton', jeton, { httpUniquement: vrai });
retour res.statut(200).json({ message: 'Connexion réussie' });
});
})(req, res, suivant);
};

Le enregistrerUtilisateur La fonction gère l'enregistrement d'un nouvel utilisateur en extrayant le nom d'utilisateur, le mot de passe et le rôle du corps de la requête. Il crée ensuite une nouvelle entrée d'utilisateur dans la base de données et répond par un message de réussite ou une erreur, le cas échéant pendant le processus.

D'autre part, le loginUser La fonction facilite la connexion de l'utilisateur en utilisant la stratégie d'authentification locale fournie par Passport.js. Il authentifie les informations d'identification de l'utilisateur et renvoie un jeton lors d'une connexion réussie qui est ensuite stocké dans un cookie pour les demandes authentifiées ultérieures. Si des erreurs se produisent pendant le processus de connexion, il renverra un message approprié.

Enfin, ajoutez le code qui implémente la logique récupérant toutes les données des utilisateurs à partir de la base de données. Nous utiliserons ce point de terminaison comme route restreinte pour nous assurer que seuls les utilisateurs autorisés ayant le rôle de administrateur peut accéder à ce point de terminaison.

exports.getUsers = asynchrone (req, res) => {
essayer {
constante utilisateurs = attendre Utilisateur.find({});
res.json (utilisateurs);
} attraper (erreur) {
console.log (erreur);
res.statut(500).json({ message: 'Une erreur s'est produite!' });
}
};

Configurer une stratégie d'authentification locale Passport.js

Pour authentifier les utilisateurs après qu'ils ont fourni leurs identifiants de connexion, vous devez configurer une stratégie d'authentification locale.

Créer un nouveau middleware/passport.js fichier dans le répertoire racine et ajoutez le code suivant.

constante StratégieLocale = exiger('passeport-local').Stratégie;
constante Utilisateur = exiger('../modèles/utilisateur.modèle');

module.exports = (passeport) => {
passeport.use(
nouveau StratégieLocale(asynchrone (nom d'utilisateur, mot de passe, terminé) => {
essayer {
constante utilisateur = attendre User.findOne({ nom d'utilisateur });

si (!utilisateur) {
retour fait(nul, FAUX);
}

si (user.password !== mot de passe) {
retour fait(nul, FAUX);
}

retour fait(nul, utilisateur);
} attraper (erreur) {
retour fait (erreur);
}
})
);
};

Ce code définit une stratégie de passeport.js local pour authentifier les utilisateurs en fonction de leur nom d'utilisateur et de leur mot de passe fournis.

Dans un premier temps, il interroge la base de données pour trouver un utilisateur avec un nom d'utilisateur correspondant, puis procède à la validation de son mot de passe. Par conséquent, il renvoie l'objet utilisateur authentifié si le processus de connexion réussit.

Créer un middleware de vérification JWT

À l'intérieur de middleware, créez un nouveau fichier auth.js et ajoutez le code suivant pour définir un middleware qui génère et vérifie les JWT.

constante jwt = exiger('jsonwebtoken');
constante secretKey = process.env. CLEF SECRÈTE;

constante générer un jeton = (charge utile) => {
constante jeton = jwt.sign (charge utile, clé secrète, { expire dans: '1h' });
retour jeton;
};

constante vérifierJeton = (rôle requis) =>(req, res, suivant) => {
constante jeton = req.cookies.token ;

si (!jeton) {
retour res.statut(401).json({ message: 'Aucun jeton fourni' });
}

jwt.verify (token, secretKey, (err, décodé) => {
si (erre) {
retour res.statut(401).json({ message: 'Jeton invalide' });
}

req.userId = décodé.userId;

si (decodé.rôle !== rôle requis) {
retour res.statut(403).json({
message: 'Vous n'avez pas l'autorisation et les permissions pour accéder à cette ressource.'
});
}

suivant();
});
};

module.exports = { générerToken, vérifierToken } ;

Le générer un jeton La fonction crée un JWT avec un délai d'expiration spécifié, tandis que le vérifier le jeton La fonction vérifie si le jeton est présent et valide. En outre, il vérifie également que le jeton décodé contient le rôle requis, garantissant essentiellement que seuls les utilisateurs disposant du rôle et des autorisations autorisés y ont accès.

Pour signer de manière unique les JWT, vous devez générer une clé secrète unique et l'ajouter à votre .env fichier comme indiqué ci-dessous.

SECRET_KEY="Ceci est un exemple de clé secrète."

Définir les routes d'API

Dans le répertoire racine, créez un nouveau dossier et nommez-le routes. Dans ce dossier, créez un nouveau userRoutes.js, et ajoutez le code suivant.

constante exprimer = exiger('exprimer');
constante routeur = express. Routeur();
constante userControllers = exiger('../controllers/userController');
constante {verifyToken} = exiger('../middleware/auth');

routeur.post('/api/s'inscrire', userControllers.registerUser);
routeur.post('/api/connexion', userControllers.loginUser);

routeur.get('/api/utilisateurs', vérifierJeton('administrateur'), userControllers.getUsers);

module.exports = routeur ;

Ce code définit les routes HTTP pour une API REST. Le utilisateurs route spécifiquement, les serveurs comme route protégée. En limitant l'accès aux utilisateurs avec le administrateur rôle, vous appliquez efficacement le contrôle d'accès basé sur les rôles.

Mettre à jour le fichier du serveur principal

Ouvrez votre serveur.js fichier et mettez-le à jour comme suit :

constante exprimer = exiger('exprimer');
constante cors = exiger('cors');
constante cookieParser = exiger('analyseur de cookies');
constante app = express();
constante port = 5000;
exiger('dotenv').config();
constante connectDB = exiger('./utils/db');
constante passeport = exiger('passeport');
exiger('./middleware/passeport')(passeport);

connectDB();

app.use (express.json());
app.use (express.urlencodé({ étendu: vrai }));
app.use (cors());
app.use (cookieParser());
app.use (passport.initialize());

constante userRoutes = exiger('./routes/userRoutes');
app.use('/', userRoutes);

app.listen (port, () => {
console.enregistrer(`Le serveur s'exécute sur le port ${port}`);
});

Enfin, démarrez le serveur de développement pour exécuter l'application.

nœud serveur.js

Tirez parti du mécanisme RBAC pour améliorer vos systèmes d'authentification

La mise en œuvre d'un contrôle d'accès basé sur les rôles est un moyen efficace d'améliorer la sécurité de vos applications.

Bien que l'intégration de bibliothèques d'authentification existantes pour établir un système RBAC efficace soit une excellente approche, tirer parti des bibliothèques RBAC pour définir explicitement les rôles d'utilisateur et attribuer des autorisations fournit une solution encore plus robuste, améliorant finalement la sécurité globale de votre application.