Как использовать проверку подлинности HTTP с помощью дополнительного токена omniauth в качестве токена аутентификации

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

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

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

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

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

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

Как я могу наилучшим образом выполнить это в конструкторе разработки?

Ответ 1

Просто сделал это, но никогда не видел сквозного решения.

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

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

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

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

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

Это решение реализует стратегию надзора, основанную на разработке стратегии Authenticatable warden. Разница здесь в том, что эта стратегия использует 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/initializers добавьте следующее в 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 с обеих сторон, что, как я подозреваю, большинство людей захотят сделать. Вероятно, это влияет на вашу схему кэширования.

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

Ответ 2

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

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

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

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