Les instructions suivantes indiquent les modifications à apporter au Prototype de niveau 5 pour atteindre le Prototype de niveau 6.
$ npm install --save uuid redis
Afin de pouvoir maintenir une liste de jetons révoqués, nous devons être en mesure de les identifier. Pour cela, il suffit d’attribuer un numéro unique (UUID) à chaque jeton dans l’attribut JTI (Json web Token Identifier). Nous devons donc modifier le code d’émission des jetons JWT dans le fichier routes/signin.js :
// Import JWT module and UUID tool
const jwt = require('jsonwebtoken');
const uuidv4 = require('uuid/v4')
…
// Define the JWT Identifier with a UUID
let jti = uuidv4();
// sign the token
let token = jwt.sign(payload, process.env.JWT_SECRET, { expiresIn: '10m', jwtid: jti, algorithm: 'HS512'});
Chaque jeton aura désormais son propre identifiant sous la forme « bdc447d7-5e6b-479c-a434-ce707bb81a10 ». Cet identifiant sera utilisé comme clé dans notre liste noire.
Il faut maintenant que l’application se connecte à notre serveur Redis. Il suffit d’intégrer le code suivant dès le début du fichier app.js :
// Setup Redis
const MyRedis = require('redis');
const MyRedisClient = MyRedis.createClient();
MyRedisClient.on('connect', function(){
console.log('Successfully connected to Redis');
});
MyRedisClient.on('error', function(err) {
console.log('Redis error: ' + err);
process.exit();
});
Lorsque l’utilisateur se déconnecte, il faut ajouter le jeton dans la liste noire stockée sur le serveur Redis. Pour cela, il suffit de modifier le fichier routes/signout.js :
// Redis Setup
const MyRedis = require('redis');
const MyRedisClient = MyRedis.createClient();
// Signout page
router.get('/', function(req, res) {
// Add JWT in the blacklist and set expiration time
MyRedisClient.set(req.user.jti,'1');
MyRedisClient.expireat(req.user.jti, req.user.exp);
res.redirect('/');
});
Redis nous permet d’indiquer la durée de conservation souhaitée. Nous n’aurons ainsi pas besoin d’implémenter un mécanisme de purge pour supprimer les jetons expirés. La taille de la liste noire en sera ainsi limitée.
Lorsqu’un utilisateur demande l’accès à une route soumise à une authentification par jeton, nous devons nous assurer que le jeton est valide. Le jeton doit donc avoir une signature valide et ne pas avoir été révoqué. Pour cela, nous modifions la fonction de vérification dans le fichier config/MyPassport.js afin de rechercher le jeton dans la base de données Redis :
// Redis Setup
const MyRedis = require('redis');
const MyRedisClient = MyRedis.createClient();
// Configure the cookie Strategy for Passport
MyPassport.use(new MyCookieStrategy(
function (token, done) {
// Check JWT
jwt.verify(token, process.env.JWT_SECRET, function(err, payload) {
// If checking failed
if (err) {
return done(err);
}
// If user is empty
if (!payload){
return done(null, false);
}
// If token is revoked
MyRedisClient.get(payload.jti, function (err, value) {
// If checking failed
if (err) {
return done(err);
}
// If JWT is revoked
if (value !== null) {
console.log("JWT " + payload.jti + "is revoked !");
return done(null, false);
}
// If everything all right, the user will be authenticated
return done(null, payload);
});
});
}));