Статьи

Rails: аутентификация пользователя / пароля с нуля, часть I

(Примечание. Исходный код, сопровождающий эту статью, можно найти здесь .)

Сегодня мы узнаем, как реализовать простую аутентификацию пользователей в приложении Rails с нуля. Мы рассмотрим лучшие практики, чтобы помочь избежать распространенных, часто дорогостоящих ошибок.


Введение в аутентификацию пользователей

Действия, защищенные паролем, являются распространенной функцией в большинстве веб-приложений, позволяя только зарегистрированным пользователям вводить действительный пароль. Это называется «Аутентификация пользователя», и это требуется многим приложениям Rails. Давайте начнем с быстрого сценария того, как работает процесс аутентификации пользователя.

  • Регистрация: создайте нового пользователя. Этот пользователь собирается зарегистрироваться с помощью имени пользователя, пароля (который будет зашифрован в базе данных), электронной почты и т. Д.
  • Логин: позволяет пользователю войти в систему с его / ее действительным именем пользователя и паролем. Процесс аутентификации происходит путем сопоставления имени пользователя и пароля в базе данных, что позволяет пользователю получить доступ к защищенным действиям только в том случае, если данная информация успешно соответствует записанным значениям. Если нет, пользователь снова будет перенаправлен на страницу входа.
  • Ограничение доступа: создайте сеанс для хранения идентифицированного идентификатора пользователя после входа в систему, чтобы можно было легко перемещаться по дополнительным защищенным действиям, просто проверяя идентификатор пользователя в текущем сеансе.
  • Выход из системы: разрешите пользователю выйти и установить идентифицированный идентификатор пользователя в файле сеанса на ноль.

Создать пользовательскую модель и контроллер

Сначала давайте создадим наше приложение с именем User_Auth . Мы используем MySQL в качестве нашей базы данных:

$ rails new User_Auth -d mysql

Перейдите в каталог приложения в вашем терминале и сгенерируйте Модель пользователя и Контроллер. Контроллер получит новый метод в качестве параметра.

$ rails cd ./User_Auth
$ rails g model user
$ rails g controller users new


Настройте базу данных

Теперь нам нужно создать таблицу Users в базе данных. Как вы, наверное, знаете, это всего лишь простая миграция.

class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :username
t.string :email
t.string :encrypted_password
t.string :salt
t.timestamps
end
end
end

Мы добавили 4 столбца в таблицу Users (имя пользователя, адрес электронной почты, encrypted_password & salt). Помните, что мы никогда не храним пароли в виде простого текста, всегда сначала шифруем значение перед сохранением его в базе данных. Существуют различные типы методов шифрования, которые мы рассмотрим позже в этом руководстве.

«Мы никогда не храним пароли в виде простого текста, его всегда нужно сначала зашифровать, прежде чем сохранять в базе данных».

После успешного создания модели и миграции создайте базу данных и перенесите ее для создания таблицы Users .

$ rake db:create
$ rake db:migrate


Создание нового пользовательского действия

Далее напишем новые и создадим действия в UsersController.

class UsersController < ApplicationController
def new
@user = User.new
end
def create
@user = User.new(params[:user])
if @user.save
flash[:notice] = «You signed up successfully»
flash[:color]= «valid»
else
flash[:notice] = «Form is invalid»
flash[:color]= «invalid»
end
render «new»
end
end

Мы создали два основных действия:

  • new : просто создайте новый пользовательский объект, который будет отображаться в новом шаблоне (мы скоро это увидим). Шаблон включает в себя форму регистрации. Данные в этой форме будут отправлены в действие создания , описанное далее …
  • create : создает пользователя на основе параметров, переданных из нового шаблона, и сохраняет его в базе данных. Если пользователь успешно создан, перенаправьте его туда, куда вы захотите, после действия регистрации. Здесь мы помещаем «Вы успешно зарегистрировались» во флэш-хэш, чтобы указать успешность, в противном случае визуализируйте новый шаблон снова.

Шаблон формы регистрации

Перед написанием формы регистрации я создал простой макет в файле application.html.erb внутри каталога views / layout.

Теперь давайте напишем форму регистрации внутри нового шаблона.

<% @page_title = «UserAuth | Signup» %>
<div classSign_Form«>
<h1>Sign Up</h1>
<%= form_for(:user, :url => {:controller => ‘users’, :action => ‘create’}) do |f| %>
<p> Username:</br> <%= f.text_field :username%> </p>
<p> Email:</br> <%= f.text_field :email%> </p>
<p> Password:</br> <%= f.password_field :password%></p>
<p> Password Confirmation:</br> <%= f.password_field :password_confirmation%> </p>
<%= f.submit :Signup %>
<% end %>
<% if @user.errors.any? %>
<ul classSignup_Errors«>
<% for message_error in @user.errors.full_messages %>
<li>* <%= message_error %></li>
<% end %>
</ul>
<% end %>
</div>

view raw
new.html.erb
hosted with ❤ by GitHub

Здесь мы создали форму для регистрации, которая берет имя пользователя, адрес электронной почты, пароль и пароль подтверждения от пользователя. Эти значения будут отправлены как params [: user] в действие create . Оператор if проверяет наличие ошибок в случае, если пользователь вводит неверные данные.

Вы также, возможно, заметили, что форма регистрации имеет два поля: пароль и подтверждение_парафа, которые должны соответствовать пользователю в базе данных. Мы должны добавить методы attr_accessor в пользовательскую модель для их обработки.


Добавление некоторых проверок в модель пользователя

В дополнение к attr_accessors нам нужно добавить несколько правил проверки, чтобы убедиться, что входные данные соответствуют нашим требованиям.

class User < ActiveRecord::Base
attr_accessor :password
EMAIL_REGEX = /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i
validates :username, :presence => true, :uniqueness => true, :length => { :in => 3..20 }
validates :email, :presence => true, :uniqueness => true, :format => EMAIL_REGEX
validates :password, :confirmation => true #password_confirmation attr
validates_length_of :password, :in => 6..20, :on => :create
end

view raw
user.rb
hosted with ❤ by GitHub

Мы создали страницу регистрации, которая создает нового пользователя и проверяет входные данные, но мы не шифровали пароль. Прежде чем мы это сделаем, давайте поговорим о шифровании пароля.


Методы шифрования паролей

Как упоминалось ранее, никогда не храните пароли в базе данных в виде простого текста. Шифрование паролей является наилучшей практикой и является фундаментальным для всех подходов аутентификации пользователей в Rails.

Хеширование пароля

Хеширование — это процесс применения математических функций и алгоритмов к строке данных для получения уникальной выходной строки. При создании нового пользователя простой текстовый пароль хешируется и сохраняется в базе данных. Когда пользователь входит в систему, входной пароль хешируется и сравнивается с хешированным паролем, хранящимся в базе данных. Этот метод называется односторонним шифрованием, то есть одни и те же входы с одной и той же функцией хеширования всегда будут давать один и тот же результат.

Мы можем реализовать метод хеширования, используя SHA1 в Rails, используя всего две строки кода

require ‘digest/sha1’
encrypted_password= Digest::SHA1.hexdigest(password)

Солевой пароль

Из-за некоторых недостатков, которые существуют в технике хеширования паролей, таких как таблицы Rainbow , использование пароля является более безопасным способом шифрования паролей. «Соль» — это дополнительная строка данных, добавляемая к паролю перед его шифрованием. Он должен быть уникальным и случайным, чтобы сделать недостаток таблиц Rainbow бесполезным.

Шифрование с использованием соли:

salt= Digest::SHA1.hexdigest(«# We add {email} as unique value and #{Time.now} as random value»)
encrypted_password= Digest::SHA1.hexdigest(«Adding #{salt} to {password}»)

Bcrypt

Есть другой простой способ зашифровать пароли, а не создавать соль с нуля: используйте bcrypt. bcrypt-ruby — это гем ruby ​​для шифрования, и мы будем использовать его в нашем приложении.

Чтобы установить его, просто добавьте в файл gem следующее:

gem ‘bcrypt-ruby’, :require => ‘bcrypt’

view raw
Gemfile
hosted with ❤ by GitHub

и внутри вашей директории приложения запустите:

$ bundle install

view raw
bundle.sh
hosted with ❤ by GitHub

тогда вы можете просто написать:

salt = BCrypt::Engine.generate_salt
encrypted_password = BCrypt::Engine.hash_secret(password, salt)


Callbacks

Нам нужны две функции: одна для шифрования действительного пароля (в виде простого текста) перед сохранением пользовательской записи, а другая функция для назначения пароля attr_accessor для nil. Поскольку мы уже зашифровали и сохранили пароль в базе данных, мы больше не будем его использовать, и мы можем сделать это с помощью обратных вызовов before_save и after_save .

Теперь давайте добавим эти функции и обратные вызовы в модель пользователя.

before_save :encrypt_password
after_save :clear_password
def encrypt_password
if password.present?
self.salt = BCrypt::Engine.generate_salt
self.encrypted_password= BCrypt::Engine.hash_secret(password, salt)
end
end
def clear_password
self.password = nil
end

view raw
user.rb
hosted with ❤ by GitHub


Защита массовых назначений

Одна из наиболее распространенных проблем безопасности в Rails называется «уязвимость массового назначения», и она проистекает из соглашения ActiveRecord о создании методов получения и установки для всех значений атрибутов объекта ActiveRecord.

В действии создания вместо непосредственного назначения каждого атрибута по одному мы используем хэш всех значений, которые мы хотим присвоить атрибутам субъекта. Это вышеупомянутое массовое задание и суть проблемы. Есть атрибуты, которые мы не хотим, чтобы пользователь мог изменять через форму, но мы не проверяем параметры.

Чтобы избежать этого, в Rails есть два метода для защиты атрибутов от массового назначения.

  • attr_protected: все атрибуты, отмеченные как attr_protected , игнорируются при массовом назначении, и все остальные атрибуты будут доступны.
  • attr_accessible: все атрибуты marekd с attr_accessible доступны во время массового назначения, а все остальные атрибуты будут защищены.

Наконец, давайте добавим доступные атрибуты в модель пользователя

attr_accessible :username, :email, :password, :password_confirmation

view raw
user.rb
hosted with ❤ by GitHub

Это завершает процесс регистрации! Вы можете запустить свой сервер, зарегистрироваться как новый пользователь и протестировать его, чтобы убедиться, что пароль успешно зашифрован в базе данных!

Примечание. Не забудьте добавить маршрут по умолчанию в файл маршрутов! Вы можете просто откомментировать в конце файла.

match ‘:controller(/:action(/:id))(.:format)’

view raw
routes.rb
hosted with ❤ by GitHub


Еще больше делать

Еще предстоит еще много работы, прежде чем мы сможем сказать, что процесс аутентификации пользователя завершен. В моем следующем посте я расскажу о работе с сессиями и файлами cookie, ограничении доступа и настройке маршрута. Спасибо за прочтение!