2012-04-25 18 views
1

OmniAuth Facebookログインフローをサーバー側の自分のレールアプリケーションに正常に統合しました。しかし、私はまた、クライアントサイドでFacebook Javascript SDKを使用してこれを動作させようとしており、いくつかの問題にぶち当たっています。Facebook Javascript SDKとOmniAuth

EDIT:この問題は、ONLY ChromeでAND NOT SAFARIまたはFirefox

セッションコントローラで何が起こっているようだ - 私は単純にヒットした場合これは、サーバー側流

def create 

     auth = request.env['omniauth.auth'] 
     #if an authorization does not exisit, it will create a new authorization record. it will also create a new user record if a user is not currently logged in 
     unless @auth = Authorization.find_from_hash(auth) 
     # Create a new user or add an auth to existing user, depending on 
     # whether there is already a user signed in. 
     @auth = Authorization.create_from_hash(auth, current_user) 

     #add the friends array to user record. as of now only doing this on the initial user create 
     @friends = [] 
     FbGraph::User.me(@auth.user.authorization.facebook_token).fetch.friends.each do |t| 
      @friends << t.identifier 
     end 
     u = @auth.user 
     u.facebook_friends = @friends 
     u.save 

     end 

     #store a new auth token if needed (if the new token in the hash does not match the one stored in the database for authorization) 
     Authorization.check_if_new_auth_token_is_needed(auth) 

     # Log the authorizing user in. 
     self.current_user = @auth.user 

     redirect_to root_url 

    end 

上で動作します/認証/ Facebookのパスは、ユーザーが

ルート

match '/auth/:provider/callback', :to => 'sessions#create' 
に記録されます。 私は今、クライアント側流ログインを実行しようとしていますホームページビューで今すぐ

ホームページの閲覧

<script> 
$(function() { 
    $('a').click(function(e) { 
    e.preventDefault(); 
    FB.login(function(response) { 
     if (response.authResponse) { 
     $('#connect').html('Connected! Hitting OmniAuth callback (GET /auth/facebook/callback)...'); 
     // since we have cookies enabled, this request will allow omniauth to parse 
     // out the auth code from the signed request in the fbsr_XXX cookie 
     $.getJSON('/auth/facebook/callback', function(json) { 
      $('#connect').html('Connected! Callback complete.'); 
      $('#results').html(JSON.stringify(json)); 
     }); 
     } 
    }, { scope: 'email,publish_stream' }); 
    }); 
}); 
</script> 
<p id="connect"> 
      <a href="#">Connect to FB</a> 
     </p> 

     <p id="results" /> 

私は私のログに

を次のエラーを取得しています{ "エラー":{ "メッセージ": "不足している承認 コード"、 "タイプ": "OAuthException"、 "コード":1}}

基本的には、OmniauthはFB.loginアクションからのFacebookの署名付きリクエスト(通常はhttps://github.com/mkdynamic/omniauth-facebook/blob/master/example/config.ruと言われています)を受け取っていません。

私はこれが正しく動作するために取得することができたり、私が間違ってやっても何をどのように上の任意のアイデア?

+0

私は自分のアプリケーションのレイアウトファイルに適切なFacebookのSDKの初期化コードのすべてがそこにあることを追加する必要があります:あなたは、接続応答を受信したときに「handle_facebook_connect」メソッドにリダイレクトする必要があります。私はちょうど宇宙目的のためにここにそれを示していない。 – Alex

答えて

3

私はこの質問は歳で実現するが、私はそううまくいけば、これは、誰かを助け、今回、この問題に遭遇しました。

この問題に関連する2件のgithubのスレッドがあります。

if !options.provider_ignores_state && (request.params['state'].to_s.empty? || request.params['state'] != session.delete('omniauth.state')) 
    raise CallbackError.new(nil, :csrf_detected) 
end 

request.params: https://github.com/mkdynamic/omniauth-facebook/issues/73https://github.com/intridea/omniauth-oauth2/issues/31

問題の原因がomniauth-のOAuth2宝石の内側callback_phase方法では、 ['state']とsession ['omniauth.state']は両方ともnilであるため、条件は失敗し、CallbackError例外が発生します。

config.omniauth :facebook, ENV['FACEBOOK_APP_ID'], ENV['FACEBOOK_APP_SECRET'], { 
    strategy_class: OmniAuth::Strategies::Facebook, 
    provider_ignores_state: true, 
} 

それはあなたが攻撃をCSRFために開く残すことができますので、それは恒久的な解決策はありません、上記のスレッドで指摘したように:

一つの解決策は、条件を回避trueにprovider_ignores_stateを設定することです。

もう1つ注目すべきことは、ChromeはローカルホストにCookieを書き込む際に問題があることです。 lvh.meをドメインとして使用してみてください(127.0.0.1に解決されます)。問題にパッチを適用するためのコードは、通常は偉大なパスではありませんが、これらのソリューションのどちらもが、あなたは常にあなた自身のハンドラを作成して、Facebookのクッキーを解析することができます作業する場合

より:

def handle_facebook_connect 
    @provider = 'facebook' 
    @oauth = Koala::Facebook::OAuth.new(ENV["FACEBOOK_ID"], ENV["FACEBOOK_SECRET"]) 
    auth = @oauth.get_user_info_from_cookies(cookies) 

    # Get an extended access token 
    new_auth = @oauth.exchange_access_token_info(auth['access_token']) 
    auth['access_token'] = new_auth["access_token"] 

    # Use the auth object to setup or recover your user. The following is 
    # and example of how you might handle the response 
    if authentication = Authentication.where(:uid => auth['user_id'], :provider => @provider).first 
     user = authentication.user 
     sign_in(user, :event => :authentication) 
    end 

    # Redirect or respond with json 
    respond_to do |format| 
     format.html { redirect_to user } 
     format.json { render json: user } 
    end 
end 

その後'LL

FB.Event.subscribe('auth.authResponseChange', function(response) { 
    if(response.status === 'connected'){ 
    if(response.authResponse){ 

     // Redirect to our new handler 
     window.location = '/handle_facebook_connect'; 

     // Or make an ajax request as in the code in the original question: 
     // $.getJSON('/handle_facebook_connect', function(json) { 
     // $('#connect').html('Connected! Callback complete.'); 
     // $('#results').html(JSON.stringify(json)); 
     // }); 

    } 
    } else if (response.status === 'not_authorized'){ 
    Facebook.message(Facebook.authorize_message); 
    } else { 
    FB.login(); 
    } 
});