手动传递signed_pa​​rameters后的Facebook NoAuthorizationError

时间:2014-09-13 01:46:02

标签: javascript facebook facebook-javascript-sdk omniauth omniauth-facebook

我尝试让客户端登录工作时遇到很多问题,因此我可以冒昧地引用其他许多问题......没有任何问题导致一个对我有用的答案。

CONTEXT

  • 服务器端登录正常
  • 使用JS SDK的客户端登录在Safari *上运行正常(未在Firefox或IE或移动非Chrome中测试过),但不在Chrome中,这就是这个问题(我的大多数用户都使用Chrome,因此它非常重要)
  • 宝石版本:
    • ruby​​(2.1.2)
    • rails(4.1.1)
    • oauth(0.4.7)
    • oauth2(1.0.0)
    • omniauth(1.2.2)
    • omniauth-facebook(2.0.0)
    • omniauth-oauth2(1.2.0)
  • 这适用于处于开发模式的应用,作为开发人员,我绝对有权登录

*工作正常,我的意思是如果你只是复制了Ryan Bates的代码' RailsCast(http://railscasts.com/episodes/360-facebook-authentication?view=asciicast)它没有任何额外的任何东西


TL:DR;我传递了以下应该有效的网址

`http://localhost:3000/auth/facebook/callback?signed_request=ASDF.JOUYOUY`
// Obviously signed_request is a much longer string

...但仍然收到错误 OmniAuth::Strategies::Facebook::NoAuthorizationCodeError (must pass either a代码parameter or a signed request (via signed_request parameter or a fbsr_XXX cookie)):


故障排除日期+许多其他错误/可能的解决方案概述

以下代码解决方案基于Ryan Bates的代码' RailsCast:

$('#sign_in').click (e) ->
  e.preventDefault()
  FB.login (response) ->
    window.location = '/auth/facebook/callback' if response.authResponse

障碍#1:第三方Cookie被阻止了吗?

不一定会导致错误,只是为了让您无法将应用程序连接到Facebook。

首先将您的应用程序连接到Facebook需要您使用Facebook登录,因为代码FB.login (response) -> window.location = "/auth/facebook/callback" if response.authResponse取决于authResponse及其包含的signedRequest参数的有效性。

如果Cookie被阻止(例如,Chrome设置>高级设置>隐私>内容设置>阻止第三方Cookie已被检查),您将永远不会获得authResponse个对象。这是问题/答案组合:FB.getLoginStatus always returns status='unknown'。换句话说,如果您执行FB.getLoginStatus,无论您点击“登录”按钮多少次,状态将始终按照unknown按文档返回https://developers.facebook.com/docs/reference/javascript/FB.getLoginStatus

到目前为止

代码解决方案...... :如果FB.login返回unknown的响应,则转回服务器端登录。

$('#sign_in').click (e) ->
  e.preventDefault()
  FB.login (response) ->
    if response.status is "unknown"
      window.location = "/auth/facebook"
    else
      window.location = "/auth/facebook/callback"

障碍#2:参数是否正确传递?

如果您取消阻止第三方Cookie,则可能会遇到错误:

OmniAuth::Strategies::Facebook::NoAuthorizationCodeError (must pass either a `code` parameter or a signed request (via `signed_request` parameter or a `fbsr_XXX` cookie)):

尽管在cookie: true中设置了FB.init,但有时params仍未通过。如下所述:

...您可能需要手动传入signed_request参数。快速注意。根据Facebook文档(https://developers.facebook.com/docs/facebook-login/using-login-with-games),signedRequest需要将两个组件分隔为.。不知道如何,但我之前没有.。分离很重要,因为后半部分是包含base64url信息的code编码JSON对象。

到目前为止

代码解决方案...... :手动将signed_request参数附加到回调网址

$('#sign_in').click (e) ->
  e.preventDefault()
  FB.login (response) ->
    if response.status is "unknown"
      window.location = "/auth/facebook"
    else
      window.location = ("/auth/facebook/callback?signed_request=" + response.authResponse.signedRequest)

障碍#3:仍然没有......仍然与#2相同的错误

在这一点上也许只是我?

到目前为止

代码解决方案...... :超级迂腐,从code解析signedRequest并追加到回调网址

$('#sign_in').click (e) ->
  e.preventDefault()
  FB.login (response) ->
    if response.status is "unknown"
      window.location = "/auth/facebook"
    else
      parsed_signed_Request = response.authResponse.signedRequest.split(".")
      key_info = base64_decode(parsed_signed_Request[1])
      // decoded via http://www.simplycalc.com/base64-source.php
      key_info_object = jQuery.parseJSON( key_info )
      window.location = ("/auth/facebook/callback?code=" + key_info_object["code"])

障碍#4:检测到CSRF,但不是为什么你认为

现在我已经进入了一堵砖墙。当我运行上面的代码时,我收到一个错误CSRF检测到。可能会出现此错误的原因不相关:

  • 如果您的Facebook应用处于开发模式并且您尝试登录用户,则可能会收到此错误。在这种情况下,FB不允许任何未列出的开发人员登录。请参阅此问题的第一个答案:Rails + omniauth + facebook - csrf detected

但是我的案例中的问题不是上述问题,而是code参数没有state参数。现在,已经有答案说您可以通过在provider_ignores_state: true配置文件中设置omniauth.rb来解决此问题,请参阅上面引用的问题的第二个答案,但这不是我的修复。为什么?因为1)我不喜欢将专门设计用于反对CSRF的东西关闭,2)看起来配置仅在服务器端登录时启动。添加它根本就没有为我做任何事情。

这意味着#3解决方案的更大问题在于它尝试将服务器端登录方法(使用codestate参数)与客户端登录方法相结合(take {{ 1}} param)。

这意味着我回到原来的问题...如何通过signed_request以便客户端登录有效?


由于我已经对此进行了漫无边际的讨论,让我指出我已经看到的另一个错误。这个答案与Facebook错误(Dealing with Oauth 2.0-facebook gem error 100: This authorization code has been used)有关,但除此之外,我发现了其他可以触发它的东西。

根据本教程(https://coderwall.com/p/bsfitw)的建议,您signed_requestmatch都有get回调路由。但是当我这样做时,我的post向Facebook显示了两个请求,第二个显然被阻止并触发了错误。 (也意味着第一个请求确实经过,用户已经被授权/数据被保存,无论如何)。我的解决方案是设置路线:

logger

1 个答案:

答案 0 :(得分:0)

对于那些仍有这个问题的人。尽量不要使用" localhost:3000"管他呢。将/ etc / hosts更改为新的URL,如

127.0.0.1 abc.com

更改developers.facebook.com上的facebook app设置以指向新网址(而不是使用localhost:3000,将其命名为abc.com:3000)

再次使用js facebook登录尝试新登录。应该工作正常!