В первой части этой серии я объяснил, как создать приложение Rails с формой регистрации. Эта статья завершает процесс аутентификации пользователя
Метод аутентификации
Поскольку теперь мы можем сохранять зашифрованные пароли в базе данных, пришло время настроить метод аутентификации, который будет использовать имя пользователя / адрес электронной почты и пароль, чтобы выяснить, соответствует ли он пользователю в базе данных. Нам нужен запрос, чтобы сопоставить имя пользователя / адрес электронной почты и, если он найден, зашифровать введенный пароль и сравнить его с зашифрованным паролем в базе данных.
Давайте напишем метод аутентификации в пользовательской модели
def self.authenticate(username_or_email=«», login_password=«») | |
if EMAIL_REGEX.match(username_or_email) | |
user = User.find_by_email(username_or_email) | |
else | |
user = User.find_by_username(username_or_email) | |
end | |
if user && user.match_password(login_password) | |
return user | |
else | |
return false | |
end | |
end | |
def match_password(login_password=«») | |
encrypted_password == BCrypt::Engine.hash_secret(login_password, salt) | |
end |
Мы видим, что если логин_пароль совпадает, мы возвращаем объект пользователя. В противном случае метод возвращает false.
Sessions Controller и шаблон формы входа
С нашим методом аутентификации давайте создадим контроллер сессий . Контроллер SessionsController будет создавать действия входа, дома, профиля и настройки.
$ rails g controller sessions login, home, profile, setting |
Давайте сосредоточимся на шаблоне входа . Акт входа в систему состоит из формы, которая принимает имя пользователя / адрес электронной почты и пароль, передавая значения в действие login_attempt .
<% @page_title = «UserAuth | Login» -%> | |
<div class= «Sign_Form«> | |
<h1>Log in</h1> | |
<%= form_tag(:action => ‘login_attempt’) do %> | |
<p>Username or Email:</br> <%= text_field_tag(:username_or_email) %></p> | |
<p>Password:</br> <%= password_field_tag :login_password %></p> | |
<%= submit_tag(«Log In») %> | |
<% end %> | |
</div> |
Создание действия `login_attempt`
Действие login_attempt принимает параметры из формы входа и передает их методу аутентификации, который мы создали ранее. Если пользователь найден, мы перенаправляем на домашнее действие. В противном случае мы снова будем отображать шаблон входа .
class SessionsController < ApplicationController | |
def login | |
#Login Form | |
end | |
def login_attempt | |
authorized_user = User.authenticate(params[:username_or_email],params[:login_password]) | |
if authorized_user | |
flash[:notice] = «Wow Welcome again, you logged in as #{authorized_user.username}« | |
redirect_to(:action => ‘home’) | |
else | |
flash[:notice] = «Invalid Username or Password» | |
flash[:color]= «invalid» | |
render «login» | |
end | |
end | |
end |
Здесь чего-то не хватает. Нам нужно сохранить вошедшее в систему состояние пользователя. Если мы этого не сделаем, нам придется проверять подлинность перед каждым запрошенным действием, которое не является СУХИМЫМ и может быть дорогостоящим. Мы будем использовать сеанс для отслеживания состояния пользователя, проверяя его перед каждым запросом пользователя.
Посмотрим, как это сделать.
Печенье, сессии и супер-печенье
Печенье:
Мы знаем, что когда пользователь отправляет запрос на веб-сервер, он обрабатывается как новый запрос. Веб-сервер не имеет состояния, то есть он не знает и не заботится о предыдущих запросах. Простое решение для передачи состояния между запросами — куки. Веб-сервер отправляет данные в файле cookie в браузер, который сохраняет их и отправляет данные cookie обратно при каждом запросе.
Использование куки в Rails совсем несложно:
Сессии:
Однако из-за некоторых ограничений файлов cookie, таких как максимальный размер 4 КБ и тот факт, что они могут быть прочитаны, изменены или удалены, мы будем использовать сеансы. Используя сеансы, веб-сервер отправляет идентификатор в файле cookie в браузер. Идентификатор отправляется обратно при каждом запросе и используется для извлечения данных из сеанса, которые хранятся на сервере.
Использование сессий в Rails, как и куки, очень просто:
session[:name]= «Azzurrio» |
Супер-Cookie:
Запись информации о сеансе в постоянное хранилище, такое как файл или база данных, плохо масштабируется. Вместо этого мы будем использовать хранилище cookie, которое является очень быстрым и безопасным. Этот так называемый супер-cookie шифруется и помещается в сеанс, гарантируя, что пользователь не сможет прочитать или изменить его.
Конфигурация сеанса: внутри папки config / initializers вы найдете два файла конфигурации для сеансов. Первый — session_store.rb , который используется для настройки опции хранения, которую вы хотите использовать ( cookie_store — опция по умолчанию). Второй — secret_token.rb , который содержит строку, которую Rails использует для шифрования файла cookie.
Теперь вернемся к нашему приложению и сохраним состояние входа в сеанс, если пользователь авторизован. Вернуться в действие login_attempt
def login_attempt | |
authorized_user = User.authenticate(params[:username_or_email],params[:login_password]) | |
if authorized_user | |
session[:user_id] = authorized_user.id | |
flash[:notice] = «Wow Welcome again, you logged in as #{authorized_user.username}« | |
redirect_to(:action => ‘home’) | |
else | |
flash[:notice] = «Invalid Username or Password» | |
flash[:color]= «invalid» | |
render «login» | |
end | |
end |
Здесь мы создали сеансовый ключ user_id , в котором хранится идентификатор авторизованного пользователя. Это будет получено при последующих запросах.
Примечание. Рекомендуется всегда хранить идентификатор, который ссылается на объект в файле сеанса, а не на сам объект. Причина в том, что значение идентификатора просто маленькое, а весь пользовательский объект намного больше. Идентификатор может быть использован для извлечения пользователя, если это необходимо.
«Всегда храните идентификатор, который ссылается на объект в файле сеанса, а не на сам объект»
Ограничение доступа
Нам нужно проверять файл сессии каждый раз, когда пользователь запрашивает какое-либо защищенное действие. Для этого мы будем использовать метод before_filter .
before_filter — это метод для выполнения функции перед выполнением определенного действия. Он пахнет как обратные вызовы, но фильтры предназначены для контроллеров, а обратные вызовы — для моделей.
Метод before_filter принимает имя метода, выполняемого перед действием. Второй параметр — это список действий, которые мы хотим отфильтровать. Давайте добавим это в наше приложение.
В ApplicationController, который является суперклассом всех наших контроллеров, добавьте:
protected | |
def authenticate_user | |
if session[:user_id] | |
# set current user object to @current_user object variable | |
@current_user = User.find session[:user_id] | |
return true | |
else | |
redirect_to(:controller => ‘sessions’, :action => ‘login’) | |
return false | |
end | |
end | |
def save_login_state | |
if session[:user_id] | |
redirect_to(:controller => ‘sessions’, :action => ‘home’) | |
return false | |
else | |
return true | |
end | |
end |
Метод authenticate_user проверяет, доступен ли сеанс user_id . Если это так, он назначает пользовательский объект переменной экземпляра @current_user и возвращает true, позволяя выполнить действие. Если нет, верните false и перенаправьте на страницу входа. Другой метод, называемый save_login_state , предотвращает доступ пользователя к страницам регистрации и входа в систему во время входа в систему.
Добавьте вызовы before_filter в SessionsController
before_filter :authenticate_user, :only => [:home, :profile, :setting] | |
before_filter :save_login_state, :only => [:login, :login_attempt] |
и в UsersController
before_filter :save_login_state, :only => [:new, :create] |
Теперь значение @current_user можно использовать в шаблонах для представления информации о зарегистрированном пользователе.
<h2 class=’User_Header‘> <%=@current_user.username%> Profile <h2> |
Выйти
Наш цикл был бы неполным без какого-либо способа выхода из сеанса. Выход, как я упоминал ранее, очищает переменную сеанса и перенаправляет на страницу входа.
def logout | |
session[:user_id] = nil | |
redirect_to :action => ‘login’ | |
end |
Конфигурация маршрутов
Наконец, прежде чем вы сможете проверить свой код, отредактируйте файл маршрутов следующим образом:
root :to => «sessions#login» | |
match «signup», :to => «users#new» | |
match «login», :to => «sessions#login» | |
match «logout», :to => «sessions#logout» | |
match «home», :to => «sessions#home» | |
match «profile», :to => «sessions#profile» | |
match «setting», :to => «sessions#setting» |
Теперь запустите сервер, войдите в систему, перейдите к другим действиям и выйдите из системы. Довольно мило, а?
Последние мысли
Вы только что узнали, как реализовать аутентификацию на основе пароля в вашем приложении с нуля. Конечно, существуют существующие библиотеки, которые обрабатывают аутентификацию для Rails, выполняя задачи, показанные в этой статье для вас.
Давайте кратко рассмотрим наиболее распространенные библиотеки:
- Devise : Devise — самая распространенная библиотека в Rails, используемая для аутентификации с рейтингом популярности 24,874 согласно веб — сайту ruby-toolbox . Это гибкое решение для аутентификации на основе Warden. Это основанное на стойке и полное решение MVC.
- Authlogic : Authlogic представляет новый тип модели, позволяющий использовать несколько моделей с проверкой подлинности (в отличие от только модели пользователя). Это чистое и простое решение для проверки подлинности ruby, занимающее второе место в рейтинге популярности с 12.815 .
- OmniAuth : OmniAuth — это основанная на провайдере структура аутентификации для веб-приложений. Это мощный и гибкий инструмент, позволяющий разработчику делать как можно меньше, используя другие механизмы аутентификации (например, Facebook или Twitter). Его рейтинг популярности — 11,128.
Есть больше библиотек для обработки аутентификации на основе паролей, с которой вы можете ознакомиться здесь .
Вывод:
В этом руководстве мы рассмотрели весь процесс внедрения простой аутентификации на основе пользователя и пароля для вашего приложения Rails. Мы узнали, как создать нового пользователя, зашифровать пароль перед сохранением и как аутентифицировать пользователя с помощью сеанса. Наконец, мы создали действие выхода из системы, которое очищает файл сеанса и перенаправляет пользователя на страницу входа. Теперь у вас есть общее представление о том, как создать аутентификацию пользователя в Rails с нуля.
Спасибо за чтение, я надеюсь, что это было полезно и приятно.