[JavaScript, Node.JS, MongoDB] Passport.js + mongoose объединяем две коллекции
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Добрый день! Решил поделиться своими небольшими достижениями в использовании популярной библиотеки Passport.js. Задача была такой: использовать две локальные стратегии passport.js при том, что пользователи находятся в двух разных коллекциях Mongo Atlas. Я искал ответы в интернете и встретил подобные вопросы, но либо ответа нет вообще, либо все не то:
- Тут ответа не нашлось
- Тут ответ близок и даже наверно рабочий, но он работает за счет дополнительного запроса к БД
Но из этих двух вопросов мне понравился больше второй, на его основе и рассмотрим как же реализовать локальные стратегии Passport.js если пользователи находятся в разных коллекциях.И так, Дано: две коллекции пользователей в Mongo Atlas, и две локальные стратеги в Passport.js. В данной статье я не буду описывать как сделать свою локальную стратегию. Это хорошо описано в этой статье, я как раз опирался на нее, когда писал свою, рекомендую.Задача, реализовать аутентификацию учителей по логину и паролю, учеников по Фамилии и номеру класса. Тут кстати в вопросе за одно и объясняется, почему мы используем две локальных стратегии, именно потому, что способы идентификации пользователя разные (учителя- логин/пароль, ученики - Фамилия/класс)Давайте рассмотрим, что мы имеем.Коллекция учителей:
teachers = {
login: "Zayka-English",
password: "qwerty",
klass: "7Б",
...
}
Коллекция ученики:
students = {
surname: "Иванов",
klass: "7Б",
category: "Ботан",
...
}
Стратегия passport.js для входа учителей:
passport.use('teachers_login', new LocalStrategy({
// Переписываем переменные из того что пришло из формы
usernameField: 'login',
passReqToCallback: true
},
async function (req, username, password, done) {
// Поиск пользователя по логину
await Teachers.findOne({ login: username }, function (err, user) {
if (err) { return done(err); }
// проверяем результат поиска
if (!user) {
return done(null, false, req.flash('msg', ['Ошибка', ': Пользователь не найден']));
} else {
// Проверяем пароль
if (user.password == password) {
console.log("Пользователь выполнил вход");
return done(null, user);
} else {
console.log('Неправильно введен пароль!');
return done(null, false, req.flash('msg', ['Ошибка', ': Неправильно введен пароль']));
}
}
});
}
))
Стратегия passport.js для входа учеников:
passport.use('students_login', new LocalStrategy({
// Переписываем переменные из того что пришло из формы
usernameField: 'surname',
userpasswordField: 'klass',
passReqToCallback: true
},
async function (req, username, password, done) {
// Поиск пользователя по Фамилии
await Students.findOne({ surname: username }, function (err, user) {
if (err) { return done(err); }
// проверяем результат поиска
if (!user) {
return done(null, false, req.flash('msg', ['Ошибка', ': Пользователь не найден']));
} else {
// Проверяем пароль
if (user.password == password) {
console.log("Пользователь выполнил вход");
return done(null, user);
} else {
return done(null, false, req.flash('msg', ['Ошибка', ': Неправильно введен класс']));
}
}
});
}
))
Ну и конечно же сериализация и десериализация:
// Записывает id пользователя в cookie
passport.serializeUser(function (user, done) {
done(null, user.id);
});
// Проверяет пользователя по id из cookie
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
Сериализация и десериализация взяты с сайта passport.js и требуют поправки, чем мы сейчас и займемся. Вся проблема нашей задачи состоит в том, что во время входа пользователя сериализация сработает и запишет в cookie id пользователя, но при десериализации нам нужно реализовать поиск в нужной коллекции. В одном из ответов в интернете было предложено поочередно проверять обе коллекции. То есть сначала ищем id в коллекции с учителями, если там нет. то ищем в коллекции с учениками. Но такой подход использует несколько запросов к БД, что увеличивает время на десериализацию. А что если коллекций не две, а больше? Я где-то видел спрашивалось о трех коллекциях, или представим, что коллекций 5! В этом случае десериализация может происходить достаточно долго. Что же делать? А ответ оказался достаточно прост. Нам необходимо дать понять, в какой из коллекций искать id пользователя при десериализации. Давайте сделаем это. Для того, что бы это реализовать для начала в наших коллекциях добавим к объектам с пользователями некоторые флаги: Коллекция учителей:
teachers = {
login: "Zayka-English",
password: "qwerty",
klass: "7Б",
flag: "teacher", // в значении флага напишем к какой категории относится пользователь
... }
Коллекция учеников:
students = {
surname: "Иванов",
klass: "7Б",
category: "Ботан",
flag: "student", //тут делаем аналогично
...}
Теперь во время входа пользователя мы запишем в cookie не только id пользователя, но и флаг, который есть в нашем объекте User. Это делается при сериализации
passport.serializeUser(function (user, done) {
// На данный этапе в переменной user находится объект с данными пользователя
// который мы получили при его идентификации в наших стратегиях
done(null, [user.flag, user.id]);
});
Теперь после того как пользователь "представился" мы внесли в cookie массив, в котором первый элемент - это flag (категория к которой относится пользователь), а второй - это id пользователя. Теперь при десериализации нам необходимо просто проверить к какой из категорий относится пользователь и проверять его id в конкретной коллекции:
passport.deserializeUser(function(id, done) {
// На этом этапе переменная id содержит наш массив
// Если флаг "учитель", ищем id в коллекции "Учителя"
if (id[0] == "teacher"){
Teacher.findById(id[1], function(err, user) {
done(err, user);
})
// Если иное, ищем id в коллекции "Ученики"
}else{
Student.findById(id[1], function(err, user) {
done(err, user);
})
}
});
При такой реализации десериализация будет происходить именно в той коллекции, к которой относится пользователь, то есть будет происходить только один запрос к БД к конкретной коллекции.Так как у нас всего две коллекции, то выбор коллекции при десериализации мы осуществили через if/else, если у вас больше коллекций, конечно же будет уместней использовать конструкцию switchНа этом все дорогие друзья, в следующей статье я напишу как же сделать авторизацию учителя, что бы в ответе получить объект с данными учителя и с массивом объектов учеников)Использовал при написании:[url=https://learn.javascript.ru/ ]Пожалуй, лучший учебник по JavaSkript[/url]Официальная документация по Passport.jsСтатья о том, как создать свою локальную коллекцию в passport.js
===========
Источник:
habr.com
===========
Похожие новости:
- [Разработка веб-сайтов, JavaScript, Программирование, HTML] Красивое радио для браузера
- [Разработка веб-сайтов, JavaScript, Программирование, ReactJS] React Social App
- [Open source, Программирование, Геоинформационные сервисы, Визуализация данных, Научно-популярное] Google Earth Engine (GEE) как общедоступный суперкомпьютер
- [Разработка веб-сайтов, Программирование, Компиляторы, IT-стандарты] Wasp — DSL для разработки веб-приложений
- [JavaScript, Работа с 3D-графикой, WebGL] Рендеринг шрифтов для WebGL при помощи инстумента msdf-bmfont-xml и технологии MSDF
- [Разработка веб-сайтов, JavaScript, Программирование, Node.JS] Дорожная карта для разработчиков Node.js на 2021 год (перевод)
- [Разработка веб-сайтов, JavaScript, Программирование, ReactJS] Делаем интерактивный Big Mac Index на React и Quarkly
- [Разработка веб-сайтов, JavaScript, Программирование, HTML] Фреймворк Webix Jet глазами новичка. Часть 1. Композиция и навигация
- [JavaScript, Совершенный код, Интерфейсы, Функциональное программирование] Шпаргалка по функциональному программированию
- [Разработка веб-сайтов, JavaScript] Юридически значимый электронный документ (для РК) из веб формы без серверного кода
Теги для поиска: #_javascript, #_node.js, #_mongodb, #_javascript, #_passport.js, #_serializatsija (сериализация), #_deserializatsija (десериализация), #_mongo, #_kollektsii (коллекции), #_node, #_javascript, #_node.js, #_mongodb
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 24-Ноя 16:19
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Добрый день! Решил поделиться своими небольшими достижениями в использовании популярной библиотеки Passport.js. Задача была такой: использовать две локальные стратегии passport.js при том, что пользователи находятся в двух разных коллекциях Mongo Atlas. Я искал ответы в интернете и встретил подобные вопросы, но либо ответа нет вообще, либо все не то:
teachers = {
login: "Zayka-English", password: "qwerty", klass: "7Б", ... } students = {
surname: "Иванов", klass: "7Б", category: "Ботан", ... } passport.use('teachers_login', new LocalStrategy({
// Переписываем переменные из того что пришло из формы usernameField: 'login', passReqToCallback: true }, async function (req, username, password, done) { // Поиск пользователя по логину await Teachers.findOne({ login: username }, function (err, user) { if (err) { return done(err); } // проверяем результат поиска if (!user) { return done(null, false, req.flash('msg', ['Ошибка', ': Пользователь не найден'])); } else { // Проверяем пароль if (user.password == password) { console.log("Пользователь выполнил вход"); return done(null, user); } else { console.log('Неправильно введен пароль!'); return done(null, false, req.flash('msg', ['Ошибка', ': Неправильно введен пароль'])); } } }); } )) passport.use('students_login', new LocalStrategy({
// Переписываем переменные из того что пришло из формы usernameField: 'surname', userpasswordField: 'klass', passReqToCallback: true }, async function (req, username, password, done) { // Поиск пользователя по Фамилии await Students.findOne({ surname: username }, function (err, user) { if (err) { return done(err); } // проверяем результат поиска if (!user) { return done(null, false, req.flash('msg', ['Ошибка', ': Пользователь не найден'])); } else { // Проверяем пароль if (user.password == password) { console.log("Пользователь выполнил вход"); return done(null, user); } else { return done(null, false, req.flash('msg', ['Ошибка', ': Неправильно введен класс'])); } } }); } )) // Записывает id пользователя в cookie
passport.serializeUser(function (user, done) { done(null, user.id); }); // Проверяет пользователя по id из cookie passport.deserializeUser(function(id, done) { User.findById(id, function(err, user) { done(err, user); }); }); teachers = {
login: "Zayka-English", password: "qwerty", klass: "7Б", flag: "teacher", // в значении флага напишем к какой категории относится пользователь ... } students = {
surname: "Иванов", klass: "7Б", category: "Ботан", flag: "student", //тут делаем аналогично ...} passport.serializeUser(function (user, done) {
// На данный этапе в переменной user находится объект с данными пользователя // который мы получили при его идентификации в наших стратегиях done(null, [user.flag, user.id]); }); passport.deserializeUser(function(id, done) {
// На этом этапе переменная id содержит наш массив // Если флаг "учитель", ищем id в коллекции "Учителя" if (id[0] == "teacher"){ Teacher.findById(id[1], function(err, user) { done(err, user); }) // Если иное, ищем id в коллекции "Ученики" }else{ Student.findById(id[1], function(err, user) { done(err, user); }) } }); =========== Источник: habr.com =========== Похожие новости:
|
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 24-Ноя 16:19
Часовой пояс: UTC + 5