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

jam*_*mes 6 javascript facebook omniauth facebook-javascript-sdk omniauth-facebook

我在试图让客户端登录工作时遇到了很多问题,所以我将冒昧地引用其他大量问题......没有一个问题导致我的答案对我有用.

CONTEXT

  • 服务器端登录工作正常
  • 使用JS SDK的客户端登录在Safari*上运行正常(未在Firefox或IE或移动非Chrome中测试),但在Chrome中没有,这是这个问题的关键(我的大多数用户都使用Chrome,因此它超级重要)
  • 宝石版本:
    • 红宝石(2.1.2)
    • 铁轨(4.1.1)
    • oauth(0.4.7)
    • oauth2(1.0.0)
    • omn​​iauth(1.2.2)
    • omn​​iauth-facebook(2.0.0)
    • omn​​iauth-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
Run Code Online (Sandbox Code Playgroud)

...但我仍然得到错误 OmniAuth::Strategies::Facebook::NoAuthorizationCodeError (must pass either a代码parameter or a signed request (viasigned_request parameter or afbsr_XXXcookie)):


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

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

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

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

不会导致错误,只是使它无法将应用程序连接到Facebook.

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

如果Cookie被阻止(例如,Chrome浏览器设置>高级设置>隐私>内容设置>阻止第三方Cookie已被检查),您将永远无法获得authResponse对象.这是问题/答案组合:FB.getLoginStatus总是返回status ='unknown'.换句话说,如果您执行a操作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"
Run Code Online (Sandbox Code Playgroud)

障碍#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)):
Run Code Online (Sandbox Code Playgroud)

虽然设置cookie: trueFB.init,有时参数仍然没有通过.如:

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

到目前为止的代码解决方案...:手动将signed_request参数附加到回调URL

$('#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)
Run Code Online (Sandbox Code Playgroud)

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

在这一点上也许只是我?

代码解决方案至今...:进入超级迂腐,将解析出codesignedRequest,并追加到回调URL

$('#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"])
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

这意味着#3解决方案的更大问题在于它试图将服务器端登录方法(take codestateparams)与客户端登录方法(采用signed_request参数)相结合.

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


既然我已经在这方面絮絮叨叨,让我指出我见过的另一个错误.这个答案与Facebook错误有关(处理Oauth 2.0-facebook宝石错误100:已使用此授权代码),但除此之外,我发现了其他可能触发它的东西.

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

match 'auth/:provider/callback', to: 'signups#create_facebook', via: [:get]
Run Code Online (Sandbox Code Playgroud)

Mar*_*ini 0

对于那些仍然有这个问题的人。尽量不要使用“localhost:3000”或其他什么。将 /etc/hosts 更改为新的 url,例如

127.0.0.1 abc.com
Run Code Online (Sandbox Code Playgroud)

更改 Developers.facebook.com 上的 facebook 应用程序设置以指向新的 url(不要使用 localhost:3000,而是将其命名为 abc.com:3000)

并再次尝试使用 js facebook 登录进行新登录。应该可以正常工作!