Синопсис
Ранее мы изучили написание основы для нашего блога, при написании основы мы ознакомились с организацией статики, составлением модели и написанием кода контроллера. Узнали как можно работать с конфигурациями путей (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)
А теперь составим представление, оно будет иметь простейшую структуру.
<div class="container"> <div class="row"> <div class="col-md-4"></div> <div class="col-md-4"> <div class="panel panel-default"> <div class="panel-body"> <form action="/user/create" method="post"> <input type="text" name="username" placeholder="Имя Пользователя"><br> <input type="password" name="password" placeholder="Пароль"><br> <input type="hidden" name="_csrf" value="<%= _csrf %>"> <!-- Поле которое можно удалить после создания администратора --> <input type="hidden" name="admin" value="true"> <input type="submit" class="btn btn-success btn-block" value="Зарегистрироваться"> </form> </div> </div> </div> <div class="col-md-4"></div> </div> </div>
Или же вместо представления можно просто отключив csrf создать пользователя — например с помощью Postman. А потом заблокировать контроллер Пользователей.
На этом завершим написание составляющих для создания пользователей. Теперь у нас есть модель, контроллер, путь страницы регистрации, и шаблон представления.
Сессии
Для авторизации пользователей мы будем использовать встроенную в 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' },
Представление
И представление страницы входа
<div class="container"> <div class="row"> <div class="col-md-4"></div> <div class="col-md-4 text-center"> <h2>Sign-in form</h2><hr> <form action="/session/create" method="POST"> <input type="text" name="username" placeholder="Username" class="form-control" /><br> <input type="password" name="password" placeholder="password" class="form-control" /><br> <input type="submit" class="btn btn-default" value="Log-In" /> <input type="hidden" name="_csrf" value="<%= _csrf %>" /> </form> </div> <div class="col-md-4"></div> </div> </div>
Теперь мы создали возможность регистрироваться и создавать сессии (входить с систему), теперь осталось сделать страницу админ панельки, и настроить политику разграничения доступа. И так завершающий этап.
Админ Панель и Разграничение Прав
У нас будет простейшая страница админки состоящая из списка постов, и формы добавления нового поста. А также страница для редактирования уже существующих постов. Теперь создайте новый контроллер admin. Вот код нашего контроллера.
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
<div class="container text-center"> <h2>CREATE NEW</h2><br> <div class="row"> <form action="/post/create" method="POST"> <div class="col-md-6"> <input class="form-control" type="text" name="title" placeholder="Title Post"><hr> <textarea rows="3" class="form-control" name="description" placeholder="Description"></textarea> </div> <div class="col-md-6"> <textarea rows="7" class="form-control" name="content" placeholder="Content"></textarea> </div> <div class="col-md-12"> <input type="hidden" name="_csrf" value="<%= _csrf %>" /> <br><input type="submit" class="btn btn-success" value="CREATE" /> </div> </form> </div><br> <h2>POST LIST</h2> <table class="table text-left"> <tr> <th>ID</th> <th>TITLE</th> <th></th> <th></th> <th></th> </tr> <% _.each(posts, function (post) { %> <tr> <td><%= post.id %></td> <td><%= post.title %></td> <td><a href="/post/watch/<%= post.id %>" class="btn btn-info">Look</a></td> <td><a href="/post/delete/<%= post.id %>" class="btn btn-danger">Delete</a></td> <td><a href="/admin/edit/<%= post.id %>" class="btn btn-warning">Edit</a></td> </tr> <% }) %> </table> </div>
views/admin/edit.ejs
<div class="container"> <div class="row"> <div class="col-md-2"></div> <div class="col-md-8 well text-center"> <form action="/post/update" method="POST"> <h4>Title</h4> <input type="text" class="form-control" name="title" value="<%= post.title %>"><br> <h4>Description</h4> <textarea rows="3" name="description" class="form-control" value="<%= post.description %>"></textarea> <h4>Content</h4> <textarea rows="7" name="content" class="form-control" value="<%= post.content %>"></textarea> <input type="hidden" name="_csrf" value="<%= _csrf %>" /><br> <input type="submit" class="btn btn-success" value="Update"> </form> </div> <div class="col-md-2"></div> </div> </div>
А теперь займемся созданием политики.
Политика
Система разграничения прав доступа в Sails весьма удобна и проста в использовании, в нашем случае достаточно лишь сверить чтобы пользователь:
- Был Авторизован
- И являлся администратором
Чтобы выразить это в коде создадим файл нашей политики — api/policies/admin.js. И вот код нашего разграничителя.
module.exports = function (req, res, ok) { if (req.session.auth && req.session.User.admin) { return ok(); } else { return res.redirect('/login'); }; }
В данном случае коллбек возвращается для того чтобы пропустить дальнейшие действия. если результат противоположный — запретить и перенаправить на страницу входа. Для активации нашей политики на определенном контроллере — откройте файл config/policies.js и приведите его в следующий вид.
module.exports.policies = { // Default policy for all controllers and actions // (`true` allows public access) '*': true, /** * Вставляем для нашего контроллера * Admin политику admin.js, которая * ограничивает доступ. */ AdminController: { '*': 'admin' }, UserController: { create: 'admin' }, PostController: { // То что могут видеть все index : true, page : true, watch : true, // То что может только админ create : 'admin', update : 'admin', delete : 'admin', } };
На этом мы закончим написание простого блога на Sails, конечно в нем очень мало функционала и защиты — нет обработки ошибок (даже flash сообщений), нет полноценной мультипользовательской админки, но эта статья расcчитана как маленький вводный курс в этот фреймворк, дальше можете изучать его сами. В дальнейшем нарастить функционал вам не должно составить большого труда.
ссылка на оригинал статьи http://habrahabr.ru/post/224403/
Добавить комментарий