Аутентификация¶
В Node.js аутентификация чаще всего реализуется с использованием функций промежуточной обработки, предоставляемых библиотекой passport.js
, которая устанавливается с помощью npm.
npm install passport --save
Для инициализации passport.js
обязательно используется функция промежуточной обработки initialize()
.
app.use(passport.initialize())
Если аутентификация не требуется для каждого обращения пользователя к URL, а будет проходить один раз, то для установки сессии необходимо использовать функцию промежуточной обработки session()
.
app.use(passport.session())
Логин и пароль¶
Для Node.js аутентификации по логину и паролю необходимо дополнительно установить модуль passport-local
.
npm install passport-local --save
Теперь рассмотрим пример.
app.js
const express = require('express'),
app = express(),
session = require('express-session'),
passport = require('passport'),
localStrategy = require('passport-local').Strategy,
flash = require('connect-flash')
const host = '127.0.0.1'
const port = 7000
function checkAuth() {
return app.use((req, res, next) => {
if (req.user) next()
else res.redirect('/login')
})
}
passport.serializeUser((user, done) => done(null, user))
passport.deserializeUser((user, done) => done(null, user))
app.use(express.json())
app.use(express.urlencoded({ extended: true }))
app.use(session({ secret: 'you secret key' }))
app.use(flash())
app.use(passport.initialize())
app.use(passport.session())
passport.use(
new localStrategy((user, password, done) => {
if (user !== 'test_user')
return done(null, false, {
message: 'User not found',
})
else if (password !== 'test_password')
return done(null, false, {
message: 'Wrong password',
})
return done(null, { id: 1, name: 'Test', age: 21 })
})
)
app.get('/login', (req, res) => {
res.send('Login page. Please, authorize.')
})
app.use((req, res, next) => {
if (req.user) next()
else res.redirect('/login')
})
app.post(
'/login',
passport.authenticate('local', {
successRedirect: '/home',
failureRedirect: '/login',
failureFlash: true,
})
)
app.get('/home', checkAuth(), (req, res) => {
res.send("Home page. You're authorized.")
})
app.listen(port, host, function () {
console.log(`Server listens http://${host}:${port}`)
})
Здесь установлен модуль connect-flash
, который позволяет использовать flash-сообщения, используемые библиотекой passport.js
.
Начнем рассмотрение примера с маршрута /login
, определенного для метода POST
. Здесь в качестве обработчика указан метод passport.authenticate()
, которому передается два параметра:
- Тип стратегии аутентификации, в данном случае
local
означает, что это будет авторизация в пределах разрабатываемого приложения, обычно по логину и паролю; - Объект конфигурации со следующими свойствами:
successRedirect
- URL для перехода в случае успешной аутентификации;failureRedirect
- URL для перехода в случае ошибки;failureFlash
- булевое значение, еслиtrue
, то добавит flash-сообщение, переданное методуdone()
в случае ошибки.
passport.authenticate('local', {
successRedirect: '/home',
failureRedirect: '/login',
failureFlash: true
}));
Далее идем к функции промежуточной обработки passport.use()
, в которой определена логика Node.js аутентификации с помощью выбранной стратегии. В приведенном примере при создании экземпляра стратегии LocalStrategy
ее конструктору передается функция, которой передается три параметра:
- имя пользователя;
- пароль пользователя;
- callback-функция, с помощью которой задается результат процесса аутентификации.
По умолчанию ожидается, что имя пользователя и пароль находятся в теле запроса в полях username
и password
соответственно. Чтобы изменить стандартное поведение - передайте при создании стратегии первым параметром следующий объект.
passport.use(
new localStrategy(
{
usernameField: 'login',
passwordField: 'pwd',
},
(user, password, done) => {
if (user !== 'test_user')
return done(null, false, {
message: 'User not found',
})
else if (password !== 'test_password')
return done(null, false, {
message: 'Wrong password',
})
return done(null, { id: 1, name: 'Test', age: 21 })
}
)
)
Callback-функции обязательно передается два аргумента: ошибка исключения, если таковое произошло, и данные пользователя. Если аутентификация прошла неудачно по ошибке самого пользователя (неправильный логин или пароль), то первым параметром передается null
, вторым - false
. Также при неудачном входе третьим параметром можно передать объект с описанием ошибки, которая будет установлена в качестве flash-сообщения, если в методе passport.authenticate()
задан в true
параметр failureFlash
.
Данные пользователя обязательно должны содержать его идентификатор, иначе будет ошибка.
В случае успешной аутентификации в объекте запроса в свойстве user
сохраняются переданные данные пользователя. Именно по наличию данных в req.user
и определяется, аутентифицирован пользователь или нет. В примере за эту проверку отвечает функция checkAuth()
.
function checkAuth() {
return app.use((req, res, next) => {
if (req.user) next()
else res.redirect('/login')
})
}
Для записи/получения данных пользователя в сессию обязательно необходимо использовать функции промежуточной обработки passport.serializeUser()
и passport.deserializeUser()
.
passport.serializeUser((user, done) => done(null, user))
passport.deserializeUser((user, done) => done(null, user))
Функции промежуточной обработки для записи/чтения пользователя необходимы только в том случае, если используется app.use(passport.session())
.
Google и Facebook¶
Использование в Node.js библиотеки passport.js
также позволяет осуществлять аутентификацию через социальные сети. Рассмотрим аутентификацию через аккаунты Google и Facebook.
Для аутентификации через Google требуется установка модуля passport-google-oauth
.
npm install passport-google-oauth --save
Модуль поддерживает протоколы OAuth 1.0 и OAuth 2.0, но здесь рассмотрим именно OAuth 2.0 в виду того, что он является более новой версии.
app.js
const express = require('express'),
app = express(),
session = require('express-session'),
passport = require('passport'),
GoogleStrategy = require('passport-google-oauth')
.OAuth2Strategy,
flash = require('connect-flash')
const host = '127.0.0.1'
const port = 7000
passport.serializeUser((user, done) => done(null, user))
passport.deserializeUser((user, done) => done(null, user))
function checkAuth() {
return app.use((req, res, next) => {
if (req.user) next()
else res.redirect('/login')
})
}
app.use(express.json())
app.use(express.urlencoded({ extended: true }))
app.use(session({ secret: 'you secret key' }))
app.use(flash())
app.use(passport.initialize())
app.use(passport.session())
passport.use(
new GoogleStrategy(
{
clientID: 90876745, //YOUR GOOGLE_CLIENT_ID
clientSecret: '35revr-sdv6-3tswa-vzd', //YOUR GOOGLE_CLIENT_SECRET
callbackURL:
'http://www.yourdomain.com/auth/google/callback',
},
(accessToken, refreshToken, profile, done) => {
return done(null, profile)
}
)
)
app.get('/login', (req, res) => {
res.send('Login page. Please, authorize.')
})
app.get(
'/auth/google',
passport.authenticate('google', {
scope: ['email', 'profile'],
})
)
app.get(
'/auth/google/callback',
passport.authenticate('google', {
failureRedirect: '/login',
successRedirect: '/home',
})
)
app.get('/home', checkAuth(), (req, res) => {
res.send("Home page. You're authorized.")
})
app.listen(port, host, function () {
console.log(`Server listens http://${host}:${port}`)
})
Стратегии аутентификации GoogleStrategy
передаются два параметра:
- объект с параметрами вашего аккаунта Google (
GOOGLE_CLIENT_ID
иGOOGLE_CLIENT_SECRET
) и указанием маршрута, к которому нужно обратиться после процесса аутентификации; - функция, описывающая логику аутентификации и устанавливающая конечный результат; принимает следующие параметры:
accessToken
;refreshToken
;profile
- данные профиля пользователя из аккаунта Google;done
- функция, с помощью которой задается результат аутентификации (после ее вызова происходит переход на указанный в callbackURL маршрут).
Сама аутентификация начинается с обращения к маршруту /auth/google
, в котором с помощью метода passport.authenticate()
указывается тип используемой стратегии (google
) и параметры так называемого scope.
В маршруте /auth/google/callback
указывается, на какие маршруты необходимо перейти в случае успешной или неудачной аутентификации.
Проверка авторизованности пользователя осуществляется по наличию объекта user
в объект запроса.
Аутентификация через Facebook практически идентична аутентификации через Google. Сначала необходимо установить модуль passport-facebook
.
npm install passport-facebook --save
Теперь необходимо заменить описание стратегии и маршрутов-обработчиков из примера аутентификации через Google на следующее.
passport.use(new FacebookStrategy({
clientID: 90876745, //YOUR FACEBOOK_APP_ID
clientSecret: '35revr-sdv6-3tswa-vzd', //YOUR FACEBOOK_APP_SECRET
callbackURL: "http://www.yourdomain.com/auth/facebook/callback"
},
(accessToken, refreshToken, profile, done) => {
return done(null, profile);
})
);
app.get('/auth/facebook', passport.authenticate('facebook'));
app.get('/auth/facebook/callback', passport.authenticate(facebook, {
failureRedirect: '/login',
successRedirect: '/home'
}));