Сесії, cookies та аутентифікація, codenamecrud - безкоштовне навчання веб-розробки
Поняття "Сесій" засноване на тому, що стан користувача якимось чином зберігається, коли він переходить з однієї сторінки на іншу. Згадайте, що HTTP не зберігає станів, тому тільки браузер або ваше додаток може "запам'ятати" то, що потрібно запам'ятати.
У цьому уроці ви дізнаєтеся про сесіях, куках браузера і про те, як побудована аутентифікація в Rails. Ми розглянемо як аутентифікацію, створювану своїми руками, так і найбільш часто використовуваний для аутентифікації гем - Devise.
Пункти для роздумів
Постарайтеся відповісти на запропоновані питання. Після виконання завдання спробуйте відповісти на них ще раз
Кукі, Сесії і флеш
Кукі, Сесії і флеш - це три спеціальних об'єкта, які надає вам Rails 4, і які ведуть себе багато в чому як хеші. Вони використовуються для зберігання даних між запитами. Дані можуть зберігатися до наступного запиту, до закриття браузера або до моменту, коли закінчиться якийсь заздалегідь встановлений термін. Крім часу зберігання даних, різниця між цими об'єктами полягає в тому, що кожен з них має свою певну область застосування, про що буде рассказно далі.
Кукі - це пари даних по типу "ключ-значення", які зберігаються в браузері користувача до закінчення якогось певного терміну. Вони застосовні практично для будь-якого завдання, але найчастіше їх використовують, щоб зберегти користувача в тому ж місці веб-сторінки, якщо він втратить інтернет-з'єднання, або щоб зберігати прості настройки відображення сайту. Ви можете також зберігати в них дані кошика користувача або навіть паролі, але це не дуже гарна ідея, не варто зберігати в звичайних куках браузера інформацію, яка повинна бути захищеною або зберігатися між сесіями браузера. Користувач може легко втратити дані, очистивши кеш, або вкрасти / використовувати незахищені дані з куків.
Для роботи з куками Rails дає вам доступ до спеціального хешу під назвою cookies. в якому кожна пара ключ-значення збережена в окрему куку в браузері користувача. Якби ви наприклад зберегли cookies [: hair-color] = "blonde". ви змогли б відкрити інструменти розробника і побачити в браузері вашого користувача куку з ключем hair-color і значенням blonde. Видалити їх можна, використовуючи cookies.delete (: hair-color).
З кожним новим запитом до сервера браузер відправляє всі куки, і ви можете отримати до них доступ в своїх Котроллер і уявленнях (views) як до звичайного хешу. Ви також можете побачити їх термін дії, наприклад, використовуючи такий синтаксис cookies [: name] =
Особливий випадок - це коли ви хочете відстежувати дані користувача "сесії", яка включає все, що користувач робить, поки ви хочете "запам'ятовувати" це, звичайно доти, поки користувач не закриє вікно браузера. У цьому випадку кожна сторінка, яку користувач відвідав до закриття браузера буде частиною однієї сесії.
Щоб ідентифікувати сесію користувача, Rails зберігає в браузері користувача спеціальну безпечну і захищену від змін куку, яка містить весь хеш сесії (пошукайте її в інструментах розробника в браузері, в розділі "Ресурси"), і вона перестає діяти, коли браузер закривається. Коли б користувач не зробив запит до вашого додатком, цей запит автоматично включає куку сесії (як і інші куки), і ви можете використовувати її, щоб відстежувати, залягання користувач. Це все може зараз здаватися абстрактним, але дуже скоро ви побачите як це працює на практиці.
Rails дає вам доступ до хешу 'сесії' практично так само, як і до хешу 'куків'. Використовуйте змінну session в своїх уявленнях або контролерах, ось так:
- session і cookies це не справжні хеші, Rails просто прикидається, що це так, щоб вам було легше працювати з ними. Однак ви можете вважати їх хешамі, тому що вони ведуть себе дуже схоже на справжні хеші.
- Розмір даних, які ви можете зберігати в хеше сесії або куках браузера обмежений (
4kb). Цього достатньо для будь-яких "звичайних" цілей, проте не потрібно намагатися замінити цим сховищем базу даних.
Ви вже бачили і використовували flash хеш, але ми розглянемо його ще раз, тепер з позицій розуміння сесій. flash - це спеціальний хеш (ну, насправді метод, провідний себе як хеш), який зберігає дані тільки від одного запиту до наступного. Можна уявити його як session хеш, який самознищується після відкриття. Він зазвичай використовується, щоб посилати повідомлення від контролера до подання, щоб користувач міг бачити повідомлення про успішну відправку форми (або про те, що форму не вийшло відправити).
Якщо ви хочете показати повідомлення "Дякуємо за підписку!" в браузері користувача, після того, як запустили екшен #create (яке зазвичай використовує redirect_to для відправки користувача на абсолютно нову сторінку в разі успіху), як ви відправите це повідомлення про успішну підписці? Ви не можете використовувати локальну змінну (instance variable), тому що редирект змушує браузер видати абсолютно новий HTTP запит, і всі змінні губляться.
Тут вам на допомогу приходить флеш! Використовуйте для збереження flash [: success] (можете назвати як завгодно) і ці дані будуть доступні вашому уявленню до наступного запиту. Як тільки уявлення відкриє хеш, Rails зітре дані, тобто вони не будуть показані при переході користувача на нову сторінку. Це дуже спритно і зручно.
Однак вам потрібно прописати відображення флеш повідомлень в уявленнях. Зазвичай пишеться короткий хелпери, який виведе у верхній частині вікна браузера будь-яке доступне флеш повідомлення (ія). Також ви можете додати повідомленням клас, який дозволить додати до повідомлення будь-CSS-стилі, наприклад виділити: success повідомлення зеленим кольором, а: error - червоним.
фільтри контролерів
Перш, ніж ми почнемо говорити про аутентифікації, необхідно расссмотреть фільтри контролерів. Суть цих фільтрів в тому, щоб запускати якийсь код в якийсь конкретний момент, наприклад до того, як відпрацює будь-який інший код. Це важливо, тому що, наприклад якщо користувач хоче запустити дію, на яке у нього немає прав, вам потрібно припинити цей запит на корені і повернути відповідну помилку / редирект, до того, як користувач зробить будь-яке інше дію. Простіше кажучи, ви "відфільтровує" неправомірні запити.
Ми робимо це, використовуючи фільтр "before", який приймає в якості аргументу ім'я методу, який ми хочемо запустити:
Метод before_action приймає символ методу, який буде запущений перш будь-якого іншого коду в контролері. Якщо він поверне false або nil. клопотання не буде виконаний.
Ви можете призначати фільтр конкретним екшенам за допомогою оціі only. ось так: before_action: require_login, only: [: edit. update]. Або навпаки, якщо ви використовуєте опцію: except. фільтр спрацює для всіх екшенів крім зазначеного.
Краще ховати фільтруючі методи в 'private', так щоб вони були доступні тільки зі свого контролера.
Ну і останнє, фільтри можуть успадковуватися, так що якщо ви хочете застосувати фільтр до екшенам абсолютно всіх контролерів, помістіть його в файл app / controllers / application_controller.rb.
аутентифікація
Основна мета аутентифікації - це упевнитися в тому, що той, хто намагається виконати будь-яку дію, має на це право. Стандартний спосіб управління цим процесом полягає в тому, що користувач логинится через форму входу. Як тільки користувач залягання, ви відстежуєте його подальші дії за допомогою сесій, поки він не вийде.
Аутентифікація Basic і Digest
Якщо вам потрібен простий і небезпечний спосіб аутентифікації, то можна використовувати аутентифікацію HTTP Basic. Ми не будемо тут розглядати її докладно, але в загальному вона має на увазі введення імені користувача і пароля в просту форму і відправку їх (в незашифрованому вигляді) через мережу. Для цього використовується метод #http_basic_authenticate_with (приклади дивіться в розділі додаткові ресурси), і цей же метод обмежує доступ до певних контролерам для нерозпізнаних користувачів.
Для трохи більше безпечної (через HTTP) системи аутентифікації, використовуйте аутентифікацію HTTP Digest. Знову ж таки, ми не будемо її тут докладно розписувати. Вона заснована на запуск методу через #before_action і надалі виклику #authenticate_or_request_with_http_digest. який приймає блок, який повинен повернути "вірний" пароль, який повинен бути наданий.
Проблема з цими способами полягає в тому, що імена і паролі в явному вигляді знаходяться в контролері (або десь ще), так що це можна використовувати тільки як тимчасове рішення.
Створюємо свою аутентифікацію
Якщо ви хочете, щоб користувачі могли залогінитися на сайті, доведеться виконати ще кілька дій. Ми не буде розписувати їх детально, тому що ви зможете все це виконати на практиці. Однак деякі принципи знати корисно. Те, про що ми будемо говорити далі, може здатися трохи незрозумілим і далеким від реальних прикладів, проте це насправді всього лише короткий опис тих штук, які ви скоро будете впроваджувати в своєму проекті.
По-перше, ми не зберігаємо паролі в базі даних у вигляді тексту. Роблячи так, ми просто напрошуємося на неприємності (сперечаємося, ви теж Новомосковсклі новини про зламаних сайтах і утекших паролі?). Замість цього, ми зберігаємо зашифровану версію пароля ( "password digest").
Коли користувач вводить свій пароль в форму входу, замість того, щоб порівняти її з текстом пароля безпосередньо, ви шифруєте пароль. Потім ви порівнюєте хешірованного версію пароля з хешировать паролем, що зберігаються в базі. Якщо вони збігаються, у вас з'являється залогіненним користувач.
Це набагато краще, тому що, якщо ви пам'ятаєте те, про що ми говорили в уроці з безпеки в веб-розробці 101. хеші - це одностороння функція. Ви можете легко хешірованного текст пароля, однак дуже і дуже важко розшифрувати його назад і відновити вихідний пароль. Найефективніший спосіб зламати набір хеш - це зібрати величезний лист можливих паролів, хешировать їх і порівняти з тими, які ви намагаєтеся зламати (тобто це масований підбір паролів).
Rails не примушує вас робити все самостійно. Вам надається метод під назвою #has_secure_password. який ви просто вбудовуєте в модель User і він додає безліч можливостей, які вам потрібні. Щоб працювати з цим зручним методом, ви настраівате в моделі User обробку атрибутів password і password_confirmation. проте не зберігаєте ці значення в базі даних. Метод has_secure_password взаємодіє з їх значеннями, перетворюючи їх в хеші.
Щоб форматувати нову сесію користувача (коли він логинится), вам потрібно створити новий контролер (зазвичай це sessions_controller.rb) і відповідні Рауса для: new. create і: destroy. Якщо користувач передає коректні логін і пароль (а ми перевіряємо це, використовуючи метод #authenticate), ви зберігаєте ID користувача в змінну session. яку можна використовувати для підтвердження того, що користувач насправді той, ким представився. Це простий спосіб аутентифікації користувача, який використовує існуючу інфраструктуру сесій Rails, але дані в ньому зберігаються тільки поки існує сесія.
Якщо ваш користувач хоче, що його "запам'ятали" (ви, напевно, тисячу разів бачили чекбокс "запам'ятати мене" в формі входу на сайт), вам потрібен спосіб запам'ятати його на більш довгий час, ніж триває сесія браузера. Щоб це зробити, вам потрібно буде створити ще один стовпець в таблиці Users, де буде зберігатися зашифрований remember_token (взагалі ви можете назвати його як завгодно). Ви будете використовувати його, щоб зберегти рандомних рядок для цього користувача, яка буде в подальшому використана для його ідентифікації.
Зазвичай корисно мати кілька методів-хелперів для вирішення звичайних завдань: залягання користувача, перевірити, залягання він, або порівняти залогіненним користувача з іншим користувачем (це пригождается, коли поточний користувач дивиться сторінку іншого користувача, і не повинен бачити посилання на "редагування") . Ці штуки зроблять ваше життя легше, тому що ви зможете повторно використовувати їх в фільтрах контролерах, вьюха або навіть в своїх тестах.
Загальна покроковий опис:
- Додайте в таблицю Users стовпець, який буде містити password_digest користувача.
- Коли користувач зареєструється, хешіруйте його пароль і збережіть хешірованного версію в новому стовпці бази даних, за допомогою методу has_secure_password. доданого в модель User.
- Не забувайте про необхідну валідації довжини пароля і підтвердження пароля.
- Створіть контролер для сесссій (і відповідних Рауса) і використовуйте метод #authenticate. щоб користувач міг залогінитися після того як ввів вірні дані в форму входу.
- Запам'ятовуйте користувачів, створивши стовпець remember_token в таблиці Users і зберігаючи цей токен як постійну куку в браузері користувача. Обнуляти її при кожному новому вході на сайт.
- При кожному завантаженні сторінки, яка вимагає аутентифікації (і використання #before_action у відповідному контролері) насамперед перевірте порівняйте куку remember_token з базою даних, щоб зрозуміти, залягання чи вже користувач. Якщо немає, перенаправьте його на сторінку входу.
- За необхідності створіть методи-хелпери, які дозволять вам робити речі на зразок простого визначення, залягання користувач, або порівняти поточного користувача з іншим.
- Профіт.
Devise - це гем, який був створений, щоб робити за вас все вищеописане. Вам може захотітися негайно зайнятися його вивченням, але це не дуже гарна ідея для новачків. Спочатку вкрай необхідно зрозуміти базові аспекти аутентифікації. Devise також може виявитися для вас досить складним, якщо ви зіткнетеся в проблемами, які не мають стандартних рішень. Загалом, це гем більш корисний для Rails розробників середнього рівня, ніж для новачків.
Незважаючи на це, в підсумку ви будете використовувати його в більшості своїх проектів, після того як освоїте самостійно створення аутентифікації. Використовувати Devise незрівнянно краще, ніж будувати аутентифікацію своїми руками, тому що він вирішує безліч проблем і закриває потенційні лазівки в безпеці, про які ви навіть б і не подумали. Devise дозволяє вам взаємодіяти з більш просунутими системами аутентифікації при роботі з API, такими як OAuth. Тому, трохи пізніше він буде дуже для вас корисний.
Якщо коротко, Devise надає вам набір форм для реєстрації та входу на сайт, а також методи для їх впровадження. Він складається з 10 модулів (і ви можете вибрати, які саме будете використовувати). Ви встановлюєте гем 'devise' і запускаєте інсталятор, щоб перенести файли в свій додаток. Вам також потрібно буде запустити міграцію бази даних, щоб додати додаткові поля в свою таблицю Users.
Ваші завдання
висновок
Цей урок повинен був дати вам уявлення про те, наскільки складними можуть бути системи аутентифікації, проте він повинен був також прибрати наліт таємничості з механізмів роботи сайтів, на яких ви бували сотні разів. Аутентифікація - не ракетобудування, все набагато простіше, і вже скоро ви самі будете вбудовувати її в свій додаток.
додаткові ресурси
Цей розділ містить корисні посилання на додаткові матеріали. Це не обов'язково, так що розцінювати їх як щось корисне, якщо ви хочете глибше зануритися в тему