Как использовать http-аутентификацию в devise с дополнительным токеном omniauth в качестве токена аутентификации - PullRequest
7 голосов
/ 29 августа 2011

У нас есть приложение rails, которое использует devise & omniauth, чтобы разрешить вход через аутентификацию facebook. У нас также есть мобильное приложение, которое в настоящее время использует http-аутентификацию для входа в приложение rails, передавая имя пользователя и пароль или передавая токен http-аутентификации. Пока все это прекрасно работает.

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

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

Конечным результатом будет то, что мобильное приложение может войти в систему пользователя через:

1) имя пользователя / пароль или же 2) токен аутентификации http или же 3) токен omniauth (facebook)

Кроме того, в случае 3), если пользователь еще не существует в приложении rails, потребуется создать пользователя - теперь это делается уже с аутентификацией на стороне браузера, поэтому больше ничего делать не нужно.

Как мне лучше всего достичь этого в конструкции устройства?

Ответы [ 2 ]

10 голосов
/ 20 декабря 2011

Только что сделал это, но никогда не видел комплексного решения.

Это относится к пункту 3. 1 и 2 легко осуществляются с помощью устройства и документированы в другом месте.

Не так сложно добавить FB auth в ваше веб-приложение, инструкции на github для omniauth и omniauth-facebook.

Я полагаю, что следующее стоит без интеграции с omniauth-facebook, если вы хотите сделать это таким образом. Это похоже на другие подходы там. Моя идея состояла в том, чтобы попытаться использовать разработанную модель как можно точнее.

Вам понадобится камень fb_graph.

На мобильном клиенте вы соответствующим образом аутентифицируетесь с помощью FB и помещаете возвращенный токен доступа в заголовок ваших http-запросов. Я использовал заголовок fb_access_token. Так же, как обычная аутентификация, вы захотите отправить ее через SSL, чтобы избежать перехвата токена. Использование заголовка позволяет мне обмениваться базовой аутентификацией и аутентификацией FB без изменения запросов, но вы можете использовать параметр если вы предпочитаете.

Это решение реализует стратегию надзирателя, основанную на разработанной стратегии поддающегося проверке надзирателя. Разница здесь в том, что в этой стратегии используется HTTP-заголовок fb_access_token, содержащий строку токена доступа к Facebook, которая была получена с помощью мобильного приложения.

Как только вы это знаете, код довольно прост.

В файле в каталоге config / initializers добавьте следующее. Я случайно назвал мой fb_api_strategy.rb:

# authentication strategy to support API authentication over the webservice
# via facebook

require 'devise/strategies/database_authenticatable'
require 'fb_graph'
require 'warden'

module Devise
  module Strategies
    class FbMobileDatabaseAuthenticatable < Authenticatable
  def valid?
    # if we have headers with the facebook access key
    !!request.headers["fb_access_token"]
  end

  def authenticate!
    token = request.headers["fb_access_token"]
    fbuser = FbGraph::User.me(token)
    fbuser = fbuser.fetch

    user = User.find_for_facebook_mobile_client(fbuser.email)

    # this either creates a new user for the valid FB account, or attaches
    # this session to an existing user that has the same email as the FB account

    if !!user && validate(user) { true }
      user.after_database_authentication
      success!(user)
    elsif !halted? || !user
      fail(:invalid)
        end
      end
    end
  end
end

Warden::Strategies.add(:fb_database_authenticatable,
                       Devise::Strategies::FbMobileDatabaseAuthenticatable)

В config / initializer добавьте следующее в devise.rb:

  config.warden do |manager|
    manager.default_strategies(:scope => :user).unshift :fb_database_authenticatable
  end

Чтобы позволить вам либо создать пользователя, либо найти существующего пользователя на основе электронной почты FB, добавьте в свою модель пользователя следующее:

  def self.find_for_facebook_mobile_client(fb_email)
    if user = User.where(:email => fb_email).first
      user
    else
      User.create!(:email => fb_email, :password => Devise.friendly_token[0,20])
    end
  end

Я не думаю, что fb_database_authenticatable - это точное имя, но я оставлю это как упражнение для читателя. Еще одним упражнением является кэширование / сохранение токена доступа FB и, возможно, избегание RT-FB при каждом вызове. Следует отметить, что токен доступа из мобильного приложения и приложения rails будет отличаться, если вы выполните FB-аутентификацию с обеих сторон, что, как я подозреваю, большинство людей захотят сделать. Это, вероятно, влияет на вашу схему кэширования.

Я думаю, что это делает - счастливое кодирование.

0 голосов
/ 02 мая 2012

Если вы устанавливаете заголовки запросов в xcode 4.3.2, вы можете использовать:

[request setValue:@"12345" forHTTPHeaderField:@"fbaccesstoken"];

, но вы не можете использовать:

[request setValue:@"12345" forHTTPHeaderField:@"fb_access_token"]; // does NOT get set
...