7

情况:

使用 Rails 3 和 OmniAuth,我有一个使用 Facebook 策略进行身份验证的应用程序。这个应用程序被构建为同样适用于 Web 和移动界面(ala Jquery-Mobile)。

挑战在于让 OmniAuth 向移动设备提供移动版 Facebook 登录屏幕,向桌面设备提供网络版。

我已经拼凑了一个解决方案,我将把它作为答案。

4

5 回答 5

5

实际上,既然 OmniAuth::Strategies 已经是 Rack 中间件,它就更简单了。只需覆盖 request_phase 方法并检查移动 user_agent 策略中存在的 @env 实例变量:

module OmniAuth
  module Strategies
    class Facebook < OAuth2

      MOBILE_USER_AGENTS =  'webos|ipod|iphone|mobile'

      def request_phase
        options[:scope] ||= "email,offline_access"
        options[:display] = mobile_request? ? 'touch' : 'page'
        super
      end

      def mobile_request?
        ua = Rack::Request.new(@env).user_agent.to_s
        ua.downcase =~ Regexp.new(MOBILE_USER_AGENTS)
      end

    end
  end
end
于 2011-05-19T02:32:53.730 回答
4

对于现代设计/omniauth (>= 1.0),在您的 config/initializers/devise.rb 中使用它:

FACEBOOK_SETUP_PROC = lambda do |env|
  request = Rack::Request.new(env)
  mobile_device = request.user_agent =~ /Mobile|webOS/i
  request.env['omniauth.strategy'].options[:display] = mobile_device ? "touch" : "page"
end

config.omniauth :facebook, FACEBOOK_APP_ID, FACEBOOK_APP_SECRET,
  :scope => 'email,offline_access', :setup => FACEBOOK_SETUP_PROC,
  :client_options => { :ssl => { :ca_file => Rails.root.join("config/ca-bundle.crt").to_s }}
于 2012-05-30T04:46:08.030 回答
1

批准的答案有效,但我必须更改一行。对于当前版本的omniauth-facebook,我必须设置显示选项,如下所示:

options[:authorize_params] = mobile_request? ? { :display => 'touch' } : { :display => 'page' }

您可以使用我找到的“弹出”、“触摸”或“页面”。

于 2011-11-11T16:51:44.960 回答
1

我尝试了第一个解决方案,但无法正常工作。经过大量搜索后,我发现 Omniauth 有一个选项“:setup => true”,它允许动态设置参数,例如 Facebook OAuth 所需的 :display 选项。

首先打开 :setup 选项。

config.omniauth :facebook, APP_CONFIG["fb_app_id"], APP_CONFIG["fb_app_secret"], 
    {:scope => 'email, offline_access', :setup => true}

然后添加第二条路线(设置路线):

  devise_for :users, :controllers => { :omniauth_callbacks => "users/omniauth_callbacks" } do
    get '/users/auth/:provider' => 'users/omniauth_callbacks#passthru'
    get '/users/auth/:provider/setup' => 'users/omniauth_callbacks#setup'
  end

添加此控制器。如果您遵循设计手册,您可能已经拥有它。

class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
  def setup
    request.env['omniauth.strategy'].options[:display] = mobile_device? ? "touch" : "page"
    render :text => "Setup complete.", :status => 404
  end
end

将此方法添加到您的 ApplicationController 中:

def mobile_device?
  if session[:mobile_param]
    session[:mobile_param] == "1"
  else
    request.user_agent =~ /Mobile|webOS/        
  end
end

完毕!

于 2011-08-14T01:03:20.563 回答
0

我的解决方案非常复杂,需要修改 OmniAuth Facebook 策略并添加 Rack 中间件。

首先,我在 OmniAuth::Strategies::Facebook 中添加了一个类属性并更改了一个方法(我把它放在了我的 omniauth.rb 配置文件的末尾,但它属于 lib 目录):

module OmniAuth
  module Strategies
    class Facebook < OAuth2
      cattr_accessor :display # new

      def request_phase
        options[:scope] ||= "email,offline_access"
        options[:display] = OmniAuth::Strategies::Facebook.display || nil # new
        super
      end
    end
  end
end

其次,我添加了一个 Rack 中间件来确定请求是否来自移动设备,然后相应地设置显示:

module Rack
  class FacebookMobileOmniauth
    def initialize(app)
      @app = app
    end

    MOBILE_USER_AGENTS =  'palm|blackberry|nokia|phone|midp|mobi|symbian|chtml|ericsson|minimo|' +
                              'audiovox|motorola|samsung|telit|upg1|windows ce|ucweb|astel|plucker|' +
                              'x320|x240|j2me|sgh|portable|sprint|docomo|kddi|softbank|android|mmp|' +
                              'pdxgw|netfront|xiino|vodafone|portalmmm|sagem|mot-|sie-|ipod|up\\.b|' +
                              'webos|amoi|novarra|cdm|alcatel|pocket|ipad|iphone|mobileexplorer|' +
                              'mobile'

    def call(env)
      request = Request.new(env)
      if request.user_agent.to_s.downcase =~ Regexp.new(MOBILE_USER_AGENTS)
        OmniAuth::Strategies::Facebook.display = 'touch'
      else
        OmniAuth::Strategies::Facebook.display = nil
      end   
      return @app.call(env)
    end
  end
end

最后,我将 Rack 中间件添加到我的 config.ru 中:

    require ::File.expand_path('../config/environment',  __FILE__)
    use Rack::FacebookMobileOmniauth # new
    run Mystupid::Application
于 2011-04-01T19:59:41.070 回答