В этой статье мы разберём как делается на Node.js и express авторизация, и для её работы используется JWT токен, самый надёжный на данный момент тип авторизации.
Также рекомендую посмотреть нашу прошлую статью, где мы делали регистрацию на Express.js, вот по этой ссылке.
Node.js и express авторизация:
Для начала скачаем все нужные нам компоненты, все их три, это mongoose, для работы с базой данных MongoDB, passport
, для создания авторизации, passport-jwt
, для проверки токена, и jsonwebtokenну
для создания JWT токена, и конечно не забывайте про сам Express, но если вы читаете эту статью, то думаю в вашем проекте он уже работает, и как его установить я не буду показывать, но если вам интересно, то посмотрите статью «Express.js быстрый старт».
Установка нужных компонентов:
1 2 3 4 | npm install mongoose npm install passport npm install passport-jwt npm install jsonwebtoken |
После того как вы всё установили, то можете начать разработку.
Важно:
Мы не будем показывать здесь как создать модель пользователя, так как тут это не очень важно, главное чтобы был email и пароль, если вы не знаете как это сделать, то почитайте статью «Регистрация на Express.js», там это объясняется и в целом мы используем базу из статьи по ссылке.
Теперь перейдите в файл «auth.js», который должен находиться в папке «controller», первым делом импортируем все нужные компоненты в него:
1 2 3 | const bcrypt = require('bcryptjs'); const User = require('../models/User'); const jwt = require('jsonwebtoken'); |
Как видите мы импортировали модель пользователя, и библиотеку для создания JWT токена.
Дальше создадим специальную функцию, которая будет отвечать за создание JWT токена, вот как она будет выглядеть:
1 2 3 4 5 6 7 | const generateAccessToken = (id, email) => { const payload = { userId: id, email: email } return jwt.sign(payload, 'Hello', {expiresIn: "1h"}) } |
Тут мы создали стрелочную функцию, в неё передаём id пользователя и его Email, следующие делаем объект, в котором будем хранить так же id пользователя и его Email, это нужно для того, чтобы когда будем получать этот токен, мы могли идентифицировать пользователя с токеном.
Последние тут мы создаём токен, делаем это с помощью метода jwt.sign()
, первым параметром принимает объект который мы сделали выше, вторым слово которая нужно будет использовать потом, чтобы расшифровать токен и получить данные из него, третий это объект с различными параметрами.
После того как мы сделали функцию для создания токена, переходим внутри этого файла в класс authController
, который мы ещё создали в статье по регистрации ссылкой выше, внутри класса создаём метод login()
, который будет отвечать за вход на сайт.
Вот как он работает:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | async login(req, res) { try { const {email, password} = req.body const user = await Users.findOne({email}) if(!user) { return res.json({message: 'Email error', code: 2}) } const validPassword = bcrypt.compareSync(password, user.password) if(!validPassword) { return res.json({message: 'Password error', code: 2 }) } const token = generateAccessToken(user.userId, user.email); return res.json({token}) } catch (e) { console.log(e) res.status(400).json({message: 'Login error'}) } } |
Первое что вы тут замечаете, это то, что во всём коде мы будем отлавливать его ошибки, и в той части, где мы отлавливаем ошибки, мы берём email и пароль, находим пользователя по его email, и если нет, то отправляем ошибку.
Дальше проверяем пароли, с помощью метода bcrypt.compareSync()
, он позволяет сравнить два пароля, один без изменений, а другой в хешированном состояние, не хешированный он вставляется в метод первым параметром, если в итоге оказывается они не совпадают, то опять выводим ошибку.
Если всё прошло нормально, то генерируем токен и отправляем его пользователю. если во всём этом коде была ошибка, то выводи её в терминал и отправляем сообщение об ошибке.
Клиентская часть:
Тут я просто объясню что делать на стороне клиента, но я не буду показывать сам код, это как нибудь в другой статье, тут только объяснения.
Для начала полученный токен записываем в localStorage, делаем это примерно так:
1 | localStorage.setItem('token', token); |
После чего при запросе к серверу передаём наш токен, примерно так это должно выглядеть:
1 2 3 | headers: { 'Authorization': 'Bearer token' } |
Как видите здесь мы в header
или в заголовки запроса добавили параметр Authorization
, который хранит токен, но перед ним ещё ставим слово Bearer
, и после пробела, уже сам токен.
Проверка токена:
Последние что осталось рассмотреть, так это как сделать проверку токена на стороне сервера, для этого первым делом создадим папку «middleware», где будем хранить middleware функции, в неё создаём файл «authJwtMiddleware.js», и вот что в нём пишем:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | const JwtStrategy = require('passport-jwt').Strategy; const ExtractJwt = require('passport-jwt').ExtractJwt; const mongoose = require('mongoose'); const options = { jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), secretOrKey: 'Hello' } module.exports = passport => { passport.use( new JwtStrategy(options, async (payload, done) => { try { const Users = await mongoose.model('Users') const user = await Users.findOne({userId: payload.userId}); if(user) { done(null, user); } else { done(null, false); } } catch(e) { console.log(e) } }) ) } |
В начале мы импортируем JwtStrategy
и ExtractJwt
, первый нам нужен будет для получения пользователя по токену, а второй для проверки что правильно передался токен.
Последние импортируем mongoose, он нужен будет для получения пользователя, следующие создаём настройки получения токена, первый параметр это jwtFromRequest
, он обозначает откуда берём токен, и как раз тут и используем ExtractJwt
, второй параметр это secretOrKey
, это строка для дешифрование наше токена, как вы помните выше, мы использовали для шифрования слово «Hello», это значит что здесь используем его же.
Следующие возвращаем функцию которая будет обрабатывать JWT токен, внутри неё используем passport.use()
или middleware функцию, которая принимает в себя создание нового объекта класса JwtStrategy
, при создание он принимает наши настройки options
и асинхронную callback функцию, которая в свою очередь принимает payload
, в которой храниться всё что мы получили из токена, и функцию done, которая нужна для подтверждения, что всё прошло успешно или нет.
Внутри callback функции так же отлавливаем ошибки. В начале мы получаем модуль пользователя, и находим пользователя по id
, который мы получили из payload
, последние проверяем, получили мы пользователя или нет, если до, то возвращаем его, если нет, то возвращаем false
.
дальше переходим в папку «routers», и там заходим в любой файл, где есть путь в котором нам надо проверять токен, для примера я возьму случайный путь, вот что я напишу:
1 2 3 4 | ... const passport = require('passport') ... router.get('/user', passport.authenticate('jwt', {session: false}), controller.getUser); |
В начале мы импортируем passport, потом при GET запросе мы используем метод passport.authenticate()
, в качестве первого параметра он принимает тип аунтификации, у нас это JWT, второй объект с настройкам, но мы используем только один, это session: false
, то есть не использование сессий, они нам нам нужны.
Последние что осталось сделать, так это добавить не много кода в «index.js», заходим в него и вот что добавляем:
1 2 3 4 5 | const passport = require('passport'); ... app.use(passport.initialize()) require('./middleware/authJwtMiddleware')(passport) ... |
В начале мы импортируем passport
, потом инициализируем его, последние импортируем нашу middleware функцию для проверки токена и сразу запускаем passport
, вот и всё, если вы сделали всё правильно, у вас должно всё работать.
Вывод:
В этой статье вы прочитали как делается на Node.js и express авторизация с использованием JWT токенов, надеюсь вам было полезно и вы сделали авторизацию как надо.