Chat Application - Authentication
Authentication:
Sử dụng passport và jwt để xử lí authentication cho app.
1.Install:
$ npm i passport passport-jwt passport-local jsonwebtoken
2.Passport authenticate middleware:
Register:
Callback handle:
Nếu model User đã define pre-hook tự động mã hóa password khi save thì không cần set
password = await bcrypt.hash(password, 10);
thủ công nữa.Define các file
usernameField
,passwordField
passport sẽ tự động get giá trị các field trong request body và đưa vào callback các giá trị tương ứng.
// File: auth/auth.js
const passport = require('passport');
const localStrategy = require('passport-local').Strategy;
const User = require('../models/user');
const JWTStrategy = require('passport-jwt').Strategy;
const ExtractJWT = require('passport-jwt').ExtractJwt;
const bcrypt = require('bcrypt');
passport.use(
'register',
new localStrategy(
{
usernameField: 'name',
passwordField: 'password'
},
async (name, password, done) => {
try {
password = await bcrypt.hash(password, 10);
const user = await User.create({name, password});
return done(null, user);
} catch (error) {
done(error);
}
}
)
);
Sử dụng middleware tại router:
```js
// File: routes/auth.js
router.post(
'/register',
[
upload.single('avatar'),
passport.authenticate('register', {session: false})
],
async (req, res, next) => {
if (req.user) {
const user = req.user;
if (req.file) {
user.addAvatar('assets/images/' + req.file.filename);
}
return res.json({
message: 'Register successful',
status: true
});
}
return res.json({
message: 'Register fail',
status: false
});
}
);
Sử dụng 2 middleware:
upload avatar: sử dụng multer
passport authenticate register đã define ở trên.
Login:
Callback handle: Tương tự register, login xử lí find và verify user.
passport.use( 'login', new localStrategy( { usernameField: 'name', passwordField: 'password' }, async (name, password, done) => { try { const user = await User.findOne({name}); if (!user) { return done(null, false, {message: 'User not found'}); } const validate = await user.verifyPassword(password); if (!validate) { return done(null, false, {message: 'Password in correct'}); } return done(null, user, {message: 'Logged in Successfully'}); } catch (error) { return done(error); } } ) );
Sử dụng middleware tại router:
router.post( '/login', async (req, res, next) => { passport.authenticate( 'login', async (err, user, info) => { try { if (err) { return next(err); } if (!user) { const error = new Error(info.message); error.status = 401; return next(error); } req.login( user, {session: false}, async (error) => { if (error) return next(error); const body = {_id: user._id, name: user.name}; const token = jwt.sign({user: body}, 'TOKEN_SECRET'); return res.json({token, name: user.name, avatar: user.avatar, _id: user._id}); } ); } catch (error) { return next(error); } } )(req, res, next); } );
Trường hợp login thành công return token về client và các request sau sẽ kèm theo token này để verify user.
JWT middleware:
Verify token của user get được từ login
passport.use( new JWTStrategy( { secretOrKey: 'TOKEN_SECRET', jwtFromRequest: ExtractJWT.fromUrlQueryParameter('token') }, async (token, done) => { try { return done(null, token.user); } catch (error) { done(error); } } ) );
Get token trong request query param
token
, nếu get trong headers bearer thì dùng methodfromAuthHeaderAsBearerToken
(note: nếu dùng bearer token thì authenticate cho socket hiện bị lỗi chưa resolved được).{session: false}
: passport sẽ verify bằng token không dùng session.// File: app.js app.use('/user', passport.authenticate('jwt', {session: false}), userRoute); // File: routes/user.js router.get( '/profile', (req, res, next) => { res.json({ status: true, user: req.user, }) } );
Socket authentication: detail ở phần sau.
Series: