Написание простого блога на SailsJS: наглядная практика для начинающих (Часть 2)
Синопсис Ранее мы изучили написание основы для нашего блога, при написании основы мы ознакомились с организацией статики, составлением модели и написанием кода контроллера. Узнали как можно работать с конфигурациями путей (routes.js), и как работать с представлениями в SailsJS. Во второй части о написании простого блога на SailsJS, мы рассмотрим следующие пункты: Пользователи: создание. Сессии: создание (вход), разрыв (выход). Написание Админ Панели, и работа с политикой и ограничениями доступа.
Пользователи Для создания нового комплекса API вводим уже знакомую нам команду в корне нашего проекта. sails generate api user В этот раз при организации кода нам понадобится шифровать пароль, для этого нам потребуется отличный модуль password-hash, который подойдет для этой задачи. Чтобы его установить — в корне нашего проекта введите следующую команду npm install password-hash --save Параметр --save указывает на то что мы сохраним значение модуль как зависимость в package.json.Так как в предыдущем посте я уже рассмотрел базовые навыки работы с моделями и контроллерами в SailsJS — где они находятся, и как их правильно составлять, я не буду обращать внимания на уже очевидные вещи.
Модель Для нашего пользователя будет несколько атрибутов: Имя пользователя Пароль Админ — параметр доступа При составлении модели мы не должны забывать что мы хотим также сделать шифрование пароля на сервере, а также сделать несколько дополнительных вспомогательных функций основанные на работе с жизненными циклами моделей var passwordHash = require ('password-hash');
var User = {
attributes: {
username: {type: 'string', required: true, unique: true}, password: {type: 'string', required: true, minLength: 8},
admin: { type: 'boolean', defaultsTo: false }, toJSON: function () { var element = this.toObject (); delete element.password; return element; }
},
beforeCreate: function (values, next) { // Создаем зашифрованную запись пароля в БД var mainPass = passwordHash.generate (values.password); values.encryptPassword = mainPass; next (); }
};
module.exports = User;
До создания нового пользователя мы добавляем дополнительный атрибут — encryptedPassword, который представляет собой зашифрованную версию пароля.Контроллер В контроллере мы сделаем только возможность создавать пользователя, и индексную страницу. Как сделать обработчики обновления и удаления пользователя вы сможете сами по подобию того что мы сделали в контроллере постов. Вот код контроллера. module.exports = {
//@API — создание пользователя
/** * Создание нового пользователя, * в качестве параметров передаем * имя пользователя, пароль, и булевое * значение админ. После создания * пользователя он аутентифицируется * в сессии. После создания пользователя * администратора мы установим политику * admin (api/policies/admin.js) чтобы к * этой функции больше не могли обращаться * не привелегированные пользователи */ create: function (req, res) { var elem = { username: req.param ('username'), password: req.param ('password'), admin: req.param ('admin') };
User.create (elem).exec (function (err, user) { if (err) return res.send (500); req.session.auth = true; res.redirect ('/'); }); },
// @MAIN index: function (req, res) { res.view (); } };
В конфигурации путей (config/routes.js) добавим следующее. '/register' : 'UserController', В качестве простой защиты включим защиту CSRF в файле конфигурации (config/csrf.js) отредактируем строку следующим образом module.exports.csrf = true; Представление (views/user/index.ejs) А теперь составим представление, оно будет иметь простейшую структуру.
Сессии Для авторизации пользователей мы будем использовать встроенную в Sails систему сессий — это удобно и достаточно безопасно (если сравнивать с cookie) наш контроллер сессий сможет создавать сессии и уничтожать их. Создайте новый контроллер стандартным способом. Вот код нашего контроллера. var passwordHash = require ('password-hash');
module.exports = {
// @API основные функции сессии
create: function (req, res) { /** * Задаем переменные запрашиваемых * параметров, в нашем случае логин * и пароль */ var username = req.param ('username'), password = req.param ('password');
/** * Если нет логина или пароля в запросе * вывести ошибку, и перенаправить обратно * (прим. здесь лучше сделать подробную * обработку ошибок, например с flash) */
if (! username || ! password) { return res.redirect ('/session'); };
/** * Найти пользователя из запроса логина * (username — req.param ('username')) * когда пользователь найден производиться * сравнение зашифрованного пароля с паролем * который был отправлен запросом, если он * валиден, то создается внешний статус — * авторизован или нет, и дается доступ к * данным через внешний доступ сессии. Это * позволит нам в дальнейшем создать политику * для ограничивания доступа к определенным * разделам нашего блога (используя сессии) */ User.findOneByUsername (username).exec (function (err, user) { if (! user || err) return res.send (500); if (passwordHash.verify (password, user.encryptPassword)) { // Авторизовать пользователя в сессии // Дать доступ к данным авторизованного // пользователя из сессии req.session.auth = true; req.session.User = user; if (req.session.User.admin) { return res.redirect ('/admin'); }; }; }); }, /** * Создаем выход из сессии который * просматривает есть ли пользователь * в онлайне, и уничтожает сессию */ destroy: function (req, res) { User.findOne (req.session.User.id).exec (function (err, user) { if (user) { req.session.destroy (); res.redirect ('/'); } else { res.redirect ('/login'); }; }); },
// @MAIN
index: function (req, res) { res.view (); } }; Конфигурация путей '/login' : 'SessionController', '/logout' : { controller: 'session', action: 'destroy' }, Представление И представление страницы входа
Sign-in form
module.exports = { index: function (req, res) { Post.find () .sort ('id DESC') .exec (function (err, posts) { if (err) return res.send (500); res.view ({ posts: posts }); }); },
edit: function (req, res) { var Id = req.param ('id');
Post.findOne (Id).exec (function (err, post) { if (! post) return res.send (404); if (err) return res.send (500); res.view ({ post: post }); }); } }; И 2 наших представления.views/admin/index.ejs