Статьи

Как использовать Omniauth для аутентификации ваших пользователей

Я ненавижу подписываться на сайты. Я уже подписался на очень многих, используя разные имена пользователей, что вернуться к одному из них и попытаться запомнить мои учетные данные иногда невозможно. В наши дни большинство сайтов начали предлагать альтернативные способы регистрации, позволяя вам использовать свой Facebook, Twitter или даже учетную запись Google. Создание такой интеграции иногда кажется долгой и трудной задачей. Но не бойся, Омниавт здесь, чтобы помочь.

Omniauth позволяет легко интегрировать более шестидесяти провайдеров аутентификации, включая Facebook, Google, Twitter и GitHub. В этом руководстве я собираюсь объяснить, как интегрировать этих поставщиков аутентификации в ваше приложение.


Давайте создадим новое приложение Rails и добавим необходимые гемы. Я предполагаю, что вы уже установили Ruby и Ruby on Rails 3.1, используя RubyGems.

1
rails new omniauth-tutorial

Теперь откройте свой Gemfile и ссылайтесь на драгоценный камень omniauth.

1
gem ‘omniauth’

Затем, как обычно, выполните команду bundle install чтобы установить гем.


Чтобы добавить провайдера в Omniauth, вам необходимо зарегистрироваться в качестве разработчика на сайте провайдера. После того, как вы зарегистрируетесь, вы получите две строки (вроде имени пользователя и пароля), которые необходимо передать Omniauth. Если вы используете провайдера OpenID, то все, что вам нужно, это URL-адрес OpenID.

Если вы хотите использовать аутентификацию Facebook, зайдите на developers.facebook.com/apps и нажмите «Создать новое приложение».

Facebook New App

Заполните всю необходимую информацию и после завершения скопируйте идентификатор своего приложения и секрет.

Facebook Secret

Настройка Twitter немного сложнее на компьютере разработчика, поскольку они не позволяют использовать «localhost» в качестве домена для обратных вызовов. Настройка среды разработки для такого рода целей выходит за рамки данного руководства, однако я рекомендую использовать Pow, если вы работаете на Mac.


Создайте новый файл в config/initializers под названием omniauth.rb . Мы собираемся настроить наших провайдеров аутентификации через этот файл.

Вставьте следующий код в файл, который мы создали ранее:

1
2
3
Rails.application.config.middleware.use OmniAuth::Builder do
  provider :facebook, YOUR_APP_ID, YOUR_APP_SECRET
end

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


Давайте создадим наш контроллер сессий. Запустите следующий код в своем терминале, чтобы создать новый контроллер sessions , а также new , create и действия при failure .

1
rails generate controller sessions new create failure

Затем откройте файл config/routes.rb и добавьте это:

1
2
3
get ‘/login’, :to => ‘sessions#new’, :as => :login
match ‘/auth/:provider/callback’, :to => ‘sessions#create’
match ‘/auth/failure’, :to => ‘sessions#failure’

Давайте разберем это:

  • Первая строка используется для создания простой формы входа в систему, где пользователь увидит простую ссылку «Связаться с Facebook».
  • Вторая строка – перехватить ответный звонок провайдера. После того как пользователь авторизует ваше приложение, провайдер перенаправляет пользователя на этот URL, чтобы мы могли использовать его данные.
  • Последний будет использоваться, когда есть проблема, или если пользователь не авторизовал наше приложение.

Убедитесь, что вы удалили маршруты, которые были созданы автоматически при запуске команды rails generate . Они не нужны для нашего маленького проекта.

Откройте файл app/controllers/sessions_controller.rb и напишите метод create следующим образом:

1
2
3
4
5
def create
  auth_hash = request.env[‘omniauth.auth’]
 
  render :text => auth_hash.inspect
end

Это используется, чтобы убедиться, что все работает. Укажите в браузере localhost: 3000 / auth / facebook, и вы будете перенаправлены на Facebook, чтобы авторизовать свое приложение (круто, а?). Авторизуйте его, и вы будете перенаправлены обратно в свое приложение и увидите хэш с некоторой информацией. Между ними будет ваше имя, ваш идентификатор пользователя Facebook и ваш адрес электронной почты, среди прочего.


Следующим шагом является создание модели пользователя, чтобы пользователи могли зарегистрироваться, используя свои учетные записи Facebook. В консоли Rails (консоль rails console ) создайте новую модель.

1
rails generate model User name:string email:string

На данный момент наша model пользователя будет иметь только name и email . Для этого нам нужен способ распознавания пользователя при следующем входе в систему. Имейте в виду, что для этой цели у нас нет полей в модели нашего пользователя.

Идея, лежащая в основе приложения, подобного тому, которое мы пытаемся создать, заключается в том, что пользователь может выбирать между использованием Facebook или Twitter (или любого другого поставщика) для регистрации, поэтому нам нужна другая модель для хранения этой информации. Давайте создадим это:

1
rails generate model Authorization provider:string uid:string user_id:integer

У пользователя будет одна или несколько авторизаций, и когда кто-то пытается войти в систему с помощью провайдера, мы просто просматриваем авторизации в базе данных и ищем ту, которая соответствует полям uid и provider . Таким образом, мы также позволяем пользователям иметь много провайдеров, чтобы они могли позже войти в систему с помощью Facebook, Twitter или любого другого провайдера, которого они настроили!

Добавьте следующий код в файл app/models/user.rb :

1
2
has_many :authorizations
validates :name, :email, :presence => true

Это указывает, что у user может быть несколько полномочий, и что поля name и email в базе данных являются обязательными.

Далее, к вашему файлу app/models/authorization.rb добавьте:

1
2
belongs_to :user
validates :provider, :uid, :presence => true

В рамках этой модели мы обозначаем, что каждая авторизация привязана к определенному user . Мы также установили некоторые проверки.


Давайте добавим некоторый код в наш controller сессий, чтобы он регистрировал пользователя или регистрировал его, в зависимости от случая. Откройте app/controllers/sessions_controller.rb и измените метод create следующим образом:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
def create
  auth_hash = request.env[‘omniauth.auth’]
 
  @authorization = Authorization.find_by_provider_and_uid(auth_hash[“provider”], auth_hash[“uid”])
  if @authorization
    render :text => “Welcome back #{@authorization.user.name}! You have already signed up.”
  else
    user = User.new :name => auth_hash[“user_info”][“name”], :email => auth_hash[“user_info”][“email”]
    user.authorizations.build :provider => auth_hash[“provider”], :uid => auth_hash[“uid”]
    user.save
 
    render :text => “Hi #{user.name}! You’ve signed up.”
  end
end

Этот код явно нуждается в рефакторинге, но об этом мы поговорим позже. Давайте сначала рассмотрим это:

  • Мы проверяем, существует ли авторизация для этого provider и этого uid . Если таковой существует, мы приветствуем нашего пользователя обратно.
  • Если авторизации не существует, мы регистрируем пользователя. Мы создаем нового пользователя с именем и адресом электронной почты, которые предоставляет нам провайдер (в данном случае Facebook), и связываем авторизацию с provider и предоставленным нам идентификатором.

Пройди тест! Перейдите на localhost: 3000 / auth / facebook, и вы должны увидеть «Вы зарегистрировались». Если вы обновите страницу, вы должны увидеть «Welcome back».


Идеальный сценарий – позволить пользователю зарегистрироваться с помощью одного поставщика, а затем добавить другого поставщика, чтобы у него было несколько вариантов входа в систему. Наше приложение пока не позволяет этого. Нам нужно немного реорганизовать наш код. Измените метод create вашего sessions_controlller.rb чтобы он выглядел следующим образом:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
def create
  auth_hash = request.env[‘omniauth.auth’]
 
  if session[:user_id]
    # Means our user is signed in. Add the authorization to the user
    User.find(session[:user_id]).add_provider(auth_hash)
 
    render :text => “You can now login using #{auth_hash[“provider”].capitalize} too!”
  else
    # Log him in or sign him up
    auth = Authorization.find_or_create(auth_hash)
 
    # Create the session
    session[:user_id] = auth.user.id
 
    render :text => “Welcome #{auth.user.name}!”
  end
end

Давайте рассмотрим это:

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

Чтобы приведенный выше код работал, нам нужно добавить несколько методов в наши модели User и Authorization . Откройте user.rb и добавьте следующий метод:

1
2
3
4
5
6
def add_provider(auth_hash)
  # Check if the provider already exists, so we don’t add it twice
  unless authorizations.find_by_provider_and_uid(auth_hash[“provider”], auth_hash[“uid”])
    Authorization.create :user => self, :provider => auth_hash[“provider”], :uid => auth_hash[“uid”]
  end
end

Если у пользователя еще нет этого провайдера, связанного с его учетной записью, мы добавим его – просто. Теперь добавьте этот метод в ваш файл authorization.rb :

1
2
3
4
5
6
7
8
def self.find_or_create(auth_hash)
  unless auth = find_by_provider_and_uid(auth_hash[“provider”], auth_hash[“uid”])
    user = User.create :name => auth_hash[“user_info”][“name”], :email => auth_hash[“user_info”][“email”]
    auth = create :user => user, :provider => auth_hash[“provider”], :uid => auth_hash[“uid”]
  end
 
  auth
end

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

Если вы хотите попробовать это локально, вам понадобится второй поставщик аутентификации. Вы можете использовать OAuth-систему Twitter, но, как я уже говорил ранее, вам нужно будет использовать другой подход, поскольку Twitter не позволяет использовать «localhost» в качестве домена URL-адреса обратного вызова (по крайней мере, он не работает для меня). Вы также можете попробовать разместить свой код на Heroku , который идеально подходит для простого сайта, такого как тот, который мы создаем.


Наконец, мы должны, конечно, разрешить пользователям выходить из системы. Добавьте этот кусок кода в ваш контроллер сессий:

1
2
3
4
def destroy
  session[:user_id] = nil
  render :text => “You’ve logged out!”
end

Нам также нужно создать подходящий маршрут (в routes.rb ).

1
get ‘/logout’, :to => ‘sessions#destroy’

Это так просто! Если вы перейдете к localhost: 3000 / logout , ваш сеанс должен быть очищен, и вы выйдете из системы. Это облегчит использование нескольких учетных записей и поставщиков. Нам также нужно добавить сообщение, которое отображается, когда пользователи отказывают в доступе к нашему приложению. Если вы помните, мы добавили этот маршрут в начале урока. Теперь нам нужно только добавить метод в контроллер sessions :

1
2
3
def failure
  render :text => “Sorry, but you didn’t allow access to our app!”
end

И, наконец, что не менее важно, создайте страницу входа, где пользователь может щелкнуть ссылку «Подключиться к Facebook». Откройте app/views/sessions/new.html.erb и добавьте:

1
<%= link_to “Connect With Facebook”, “/auth/facebook” %>

Если вы перейдете на localhost: 3000 / login, вы увидите ссылку, которая перенаправит вас на страницу аутентификации Facebook.


Я надеюсь, что эта статья предоставила вам краткий пример того, как работает Omniauth. Это очень мощная жемчужина, которая позволяет создавать веб-сайты, которые не требуют регистрации пользователей, что всегда является плюсом! Вы можете узнать об Omniauth на GitHub .

Дайте нам знать, если у вас есть какие-либо вопросы!