1

我已成功地将 OmniAuth Facebook 登录流程集成到服务器端的 rails 应用程序中。但是,我也试图在客户端使用 Facebook Javascript SDK 让它工作,并且遇到了一些问题。

编辑:这个问题似乎只发生在 Chrome 中,而不是在 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

如果我只是点击 /auth/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" />

我的日志中出现以下错误

{"error":{"message":"缺少授权码","type":"OAuthException","code":1}}

基本上,Omniauth 并没有收到来自 FB.login 操作的 facebook 签名请求(正如https://github.com/mkdynamic/omniauth-facebook/blob/master/example/config.ru所说的那样)。

关于如何让它正常工作或我可能做错了什么的任何想法?

4

1 回答 1

3

我意识到这个问题已经有一年了,但我现在已经两次遇到这个问题,所以希望这对某人有所帮助。

有两个与此问题相关的 github 线程: https ://github.com/mkdynamic/omniauth-facebook/issues/73 和 https://github.com/intridea/omniauth-oauth2/issues/31

问题的根源是omniauth-oauth2 gem 中的callback_phase 方法:

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['state'] 和 session['omniauth.state'] 都为 nil,因此条件失败并引发 CallbackError 异常。

一种解决方案是将 provider_ignores_state 设置为 true 以规避该条件:

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

正如在上面的线程中所指出的,它不是一个永久的解决方案,因为它可能会让你容易受到 csrf 攻击。

需要注意的另一件事是 Chrome 在将 cookie 写入 localhost 时存在问题。尝试使用 lvh.me 作为您的域(解析为 127.0.0.1)。

修复问题的更多代码通常不是一条好路,但如果这些解决方案都不起作用,那么您始终可以创建自己的处理程序并解析 Facebook cookie:

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

然后,当您收到连接的响应时,您需要重定向到“handle_facebook_connect”方法:

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();
  }
 });
于 2014-02-27T22:41:59.273 回答