Если базовая авторизация не подходит – пользователи регистрируются сами, а внедрять passport.js не то чтобы рано, но надо разобраться с самого начала как оно работает. То здесь описан механизм хранения авторизации пользователя (его сессии) в Mongo, хотя можно заменить на любое поддерживаемое в express-session.
Чем cookies, отличаются от session. Сессии хранятся на сервере, ну точнее, где-то не на клиенте. Но, на клиенте в cookies хранится идентификатор сессии на сервере.
А cookies соответственно хранятся полностью на клиенте.
Модель пользователя
Для того чтобы создавать новых пользователей и проверять потом на соответствие логин/пароль будем использовать Mongoose. Первым делом надо описать модель пользователя. Файл модели может лежать где угодно, папка db/models в корне проекта вполне подойдёт.
Кстати, все примеры описанные здесь основаны на базовом express приложении, том самом которое создаётся по команде в консоли express ./
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
var mongoose = require('mongoose'); var User = new mongoose.Schema({ username : { type: String, unique: true, required: true }, password : { type: String, required: true } }) module.exports = mongoose.model('User', User) |
Одной модели к сожалению мало, надо создать функции необходимые для управления моделью. Создайте файл api.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 31 32 33 34 35 36 37 |
var mongoose = require('mongoose') var crypto = require('crypto') var User = require('./db/models/User.js') // User API exports.createUser = function(userData){ var user = { name: userData.name, email: userData.email, password: hash(userData.password) } return new User(user).save() } exports.getUser = function(id) { return User.findOne(id) } exports.checkUser = function(userData) { return User .findOne({email: userData.email}) .then(function(doc){ if ( doc.password == hash(userData.password) ){ console.log("User password is ok"); return Promise.resolve(doc) } else { return Promise.reject("Error wrong") } }) } function hash(text) { return crypto.createHash('sha1') .update(text).digest('base64') } |
Сессии! Полный вперёд!
Конечно, можно дополнить любыми своими полями, email или фотография. Так, модель готова, теперь необходимо подключить управление сессиями в приложение. Установите модули:
espress-session – необходим для управления сессиями
connect-mongo – хранение идентификаторов сессий в базе данных Mongo
Второй модуль отвечает за хранение сессий в MongoDB. Без него сессии могут храниться в оперативной памяти, в таком случае при каждой перезагрузке приложения пользователи должны будут авторизоваться заново.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
var mongoose = require("mongoose") var session = require('express-session') var MongoStore = require('connect-mongo')(session); //... app.use(session({ secret: 'i need more beers', resave: false, saveUninitialized: false, // Место хранения можно выбрать из множества вариантов, это и БД и файлы и Memcached. store: new MongoStore({ }) })) |
Механизм
Приготовления приготовлены, пришла пора создать пользователя. Несколько middleware для всех CRUD операций будут содержать всю логику управления пользователями (ну, кроме удаления, но это домашняя работа). У вас уже есть файл users.js
в папке routes, замените его содержимое.
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 31 32 33 34 35 36 37 38 39 40 41 42 43 |
var express = require('express'); var router = express.Router(); var api = require('../api.js') /* Создание пользователя */ router.post('/login', function(req, res, next) { if (req.session.user) return res.redirect('/') api.checkUser(req.body) .then(function(user){ if(user){ req.session.user = {id: user._id, name: user.name} res.redirect('/') } else { return next(error) } }) .catch(function(error){ return next(error) }) }); router.post('/', function(req, res, next) { api.createUser(req.body) .then(function(result){ console.log("User created") }) .catch(function(err){ if (err.toJSON().code == 11000){ res.status(500).send("This email already exist") } }) }); router.post('/logout', function(req, res, next) { if (req.session.user) { delete req.session.user; res.redirect('/') } }); module.exports = router; |
Уже сейчас вы можете создать пользователя. Для этого откройте любой сервис который умеет отправлять POST запрос (Postman) и предварительно запустив приложение npm start
отправьте POST-запрос:
Всё, можно проверить базу данных, где в коллекции users вы найдёте первого пользователя.
Шаблон
Осталось реализовать логин и деавторизацию. Замените файл с обработкой запросов на главную страницу, тот что index.js
в папке routes
. Следующим содержимым.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
var express = require('express'); var router = express.Router(); var api = require('../api') /* GET home page. */ router.get('/', function(req, res, next) { if(req.session.user){ var data = { title: 'Express', user : req.session.user } res.render('index', data); } else { var data = { title: 'Express', } res.render('index', data); } }); module.exports = router; |
А шаблон формы регистрации/авторизации при помощи шаблонизатора jade может выглядеть так (замените содержимое index.jade):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
if user h1= user.name p you are logged) hr a(href='/users/logout') Exit if you wish else h1 Register user form(method='post', action='/users') input(type='text', name='name') input(type='text', name='email') input(type='password', name='password') input(type='submit') h1 Login user form(method='post', action='/users/login') input(type='text', name='email') input(type='password', name='password') input(type='submit') |
Запускайте приложение, авторизуйтесь. И ищите в базе данных коллекцию sessions, а в консоли Google Chrome куки с идентификатором сессии. По-моему, круто, теперь можно делать свой Facebook/ВКонтакте.
спасибо за пример, это ровно то что мне новичку нужно,
хотя честно говоря я так и не смог его оживить.
поэтому такой вопрос/просьба – а можно от этого поста посмотреть исходники? конечный вариант.
например вот в user.js:
…
var UserModel = mongoose.model(‘User’, User);
module.exports = mongoose.model(‘User’, UserModel)
у меня вызывает ошибку:
Error: The 2nd parameter to
mongoose.model()
should be a schema or a POJOДоброго времени суток!
Спасибо за гайд. Хотелось бы только узнать куда нужно вставить кусок кода, который перед заголовком статьи “Механизм”. Просто в app.js не идет, т.к. в user.js используется session.
Спасибо еще раз!
вот так сделаю скорее всего))
Да, это работает, спасибо за простое объяснение))))
Второй параметр создания модели принимает название используемой таблицы/коллекции из БД Монго
Пример неплохой, но какова степень его безопасности? Например, пользователь может очистить историю вместе с куками, а сессия будет храниться в MongoStore еще достаточно долго, из-за чего может возникнуть переполнение хранилища. В режиме инкогнито может вообще не быть куков, тогда единственным выходом будет localStorage.