状況:
Rails 3とOmniAuthを使用して、Facebook戦略を使用して認証するアプリがあります。このアプリは、Webインターフェースとモバイルインターフェース(ala Jquery-Mobile)で同等に機能するように構築されています。
課題は、OmniAuthにFacebookのログイン画面のモバイルバージョンをモバイルデバイスに提供させ、Webバージョンをデスクトップデバイスに提供させることです。
私は答えとして置く解決策を一緒にハックしました。
状況:
Rails 3とOmniAuthを使用して、Facebook戦略を使用して認証するアプリがあります。このアプリは、Webインターフェースとモバイルインターフェース(ala Jquery-Mobile)で同等に機能するように構築されています。
課題は、OmniAuthにFacebookのログイン画面のモバイルバージョンをモバイルデバイスに提供させ、Webバージョンをデスクトップデバイスに提供させることです。
私は答えとして置く解決策を一緒にハックしました。
実際、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
最新のdevise/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 }}
承認された回答は機能しますが、1行変更する必要がありました。omniauth-facebookの現在のバージョンでは、次のように表示オプションを設定する必要がありました。
options[:authorize_params] = mobile_request? ? { :display => 'touch' } : { :display => 'page' }
私が見つけたものから「ポップアップ」、「タッチ」、または「ページ」を使用できます。
最初の解決策を試しましたが、機能させることができませんでした。多くの検索の結果、Omniauthには、Facebook OAuthに必要な:displayオプションなど、引数の動的設定を可能にするオプション ":setup=>true"があることがわかりました。
まず、:setupオプションをオンにします。
config.omniauth :facebook, APP_CONFIG["fb_app_id"], APP_CONFIG["fb_app_secret"],
{:scope => 'email, offline_access', :setup => true}
次に、2番目のルート(セットアップルート)を追加します。
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
終わり!
私のソリューションはかなり複雑で、OmniAuthFacebook戦略の変更と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
そして最後に、config.ruにRackミドルウェアを追加しました。
require ::File.expand_path('../config/environment', __FILE__)
use Rack::FacebookMobileOmniauth # new
run Mystupid::Application