手动传递signed_pa​​rameters后的Facebook NoAuthorizationError [英] Facebook NoAuthorizationError after passing signed_parameters manually

查看:174
本文介绍了手动传递signed_pa​​rameters后的Facebook NoAuthorizationError的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有很多问题需要让客户端登录工作,所以我会在这里引用一些其他问题的自由,没有一个答案有为我工作



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/epi sodes / 360-facebook-authentication?view = asciicast )它的工作没有任何额外的东西






TL:DR;我正在传递以下应该工作的URL ...

 `http:// localhost:3000 / auth / facebook / callback?signed_request = ASDF.JOUYOUY` 
//显然signed_request是一个长得多的字符串

...但仍然收到错误 OmniAuth :: Strategies :: Facebook :: NoAuthorizationCodeError(必须通过代码参数或签名请求(通过 signed_request 参数或 fbsr_XXX cookie)):






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

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

  $('#sign_in')。点击(e) - > 
e.preventDefault()
FB.login(响应) - >
window.location ='/ auth / facebook / callback'如果response.authResponse

<强>障碍#1:是否阻止了第三方Cookie?



不会导致错误,只是让它无法连接该应用程序到Facebook。



将您的应用程序连接到Facebook首先要求您使用Facebook登录,因为代码 FB.login(响应) - >如果response.authResponse 取决于 authResponse 及其包含的 signedRequest 参数。



如果Cookie被阻止(即,Chrome设置>高级设置>隐私>内容设置>阻止第三方Cookie已检查),您将永远不会收到 authResponse 对象返回。这是这里的问题/答案组合: FB.getLoginStatus总是返回status ='unknown'。换句话说,如果您执行 FB.getLoginStatus ,无论您点击登录按钮多少次,状态将始终返回为 unknown 根据文档: https://developers.facebook的.com /文档/参考/ JavaScript的/ FB.getLoginStatus



到目前为止的代码解决方案... :如果 FB.login 返回响应未知转回服务器端登录。

  $(' #sign_in')。点击(e) - > 
e.preventDefault()
FB.login(响应) - >
如果response.status是未知
window.location =/ auth / facebook
else
window.location =/ auth / facebook / callback

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



如果您有第三方Cookie解除封锁,您可能会遇到错误:

  OmniAuth :: Strategies :: Facebook :: NoAuthorizationCodeError(必须通过`code`参数或签名的请求(通过`signed_request`参数或`fbsr_XXX` cookie)):

尽管在 FB.init 中设置 cookie:true 有时候params仍然没有通过。如下所述:





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

迄今为止的代码解决方案... :手动追加 signed_request 参数回调URL



  $('#sign_in')点击(e) - > 
e.preventDefault()
FB.login(响应) - >
如果response.status是unknown
window.location =/ auth / facebook
else
window.location =(/ auth / facebook / callback?signed_request = + response.authResponse.signedRequest

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



在这一点上也许只是我?



到目前为止的代码解决方案... :去超级学习,解析出代码 signedRequest 并追加到回调URL

  $('# sign_in')。点击(e) - > 
e.preventDefault()
FB.login(响应) - >
如果response.status是未知
window.location =/ auth / facebook
else
parsed_signed_Request = response.authResponse.signedRequest.split(。)
key_info = base64_decode(parsed_signed_Request [1])$ ​​b $ b //通过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检测到



但是我的情况不是上面的问题,就是在代码参数中没有出现状态参数。现在,有一些答案说你可以通过在 omniauth.rb 配置文件中设置 provider_ignores_state:true 来解决这个问题,见上面提到的第二个问题的答案,但这不是我的一个修复。为什么?因为1)我不喜欢转而专门设计来防止CSRF关闭的东西,2)配置只能在服务器端登录。添加它根本没有为我做任何事情。



这意味着#3解决方案的更大问题是它试图结合服务器端登录方法使用客户端登录方法的代码状态 params)(需要 signed_request param)。



这意味着我回到原来的问题...如何传递 signed_request 使客户端登录有效?






由于我已经漫游了,让我指出另一个我看到的错误。这一个有关于Facebook错误的答案(处理Oauth 2.0-facebook宝石错误100:这个授权代码已被使用),但除此之外,我发现可以触发它的其他东西。



如本教程中的建议( https:// coderwall .com / p / bsfitw ),您匹配通过获取。但是当我这样做时,我的记录器向Facebook显示两个请求,第二个显然被阻止并触发错误。 (也意味着第一个请求已经通过,用户已经被授权/数据被保存,无论如何)。我的解决方案是设置路由:

 匹配'auth /:提供者/回调',到:'注册#create_facebook' ,通过:[:get] 


解决方案

有这个问题。尽量不要使用localhost:3000或其他。将/ etc / hosts更改为新的URL,如

  127.0.0.1 abc.com 

在developers.facebook.com上更改Facebook应用设置,指向新的URL(而不是使用localhost:3000,称之为abc.com:3000 )



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


I've had a lot of issues trying to get the client-side login to work, so I'm going to take the liberty of referencing a ton of other questions here... none have resulted in an answer that has worked for me.

CONTEXT

  • Server-side login works fine
  • Client-side login using JS SDK works fine on Safari* (have not tested in Firefox or IE or mobile non-Chrome), but not in Chrome, which is what this question is about (and majority of my users use Chrome so it's super important)
  • Gem versions:
    • 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)
  • This is for an app in development mode, where as the developer, I am definitely authorized to log in

*By works fine, I mean if you just copied the code from Ryan Bates' RailsCast (http://railscasts.com/episodes/360-facebook-authentication?view=asciicast) it works without any additional anything


TL:DR; I'm passing the following URL which should work...

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

...but am still getting the error OmniAuth::Strategies::Facebook::NoAuthorizationCodeError (must pass either acodeparameter or a signed request (viasigned_requestparameter or afbsr_XXXcookie)):


TROUBLESHOOTING TO DATE + OVERVIEW OF MANY OTHER ERRORS/ POTENTIAL SOLUTIONS

The code solutions below build on the code from Ryan Bates' RailsCast:

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

Hurdle #1: Are 3rd party cookies blocked?

Doesn't lead to an error necessarily, just makes it so that you can't connect the app to Facebook.

Connecting your app to Facebook first requires you to be logged in with Facebook because the code FB.login (response) -> window.location = "/auth/facebook/callback" if response.authResponse depends on the validity of authResponse and its contained signedRequest parameter.

If cookies are blocked (i.e., Chrome Settings > Advanced Settings > Privacy > Content Settings > Block Third Party Cookies is CHECKED), you will never get a authResponse object back. This is the question/answer combination here: FB.getLoginStatus always returns status='unknown'. In other words, if you do a FB.getLoginStatus, regardless of how many times you click a Login button, the status will always return back as unknown per the docs: https://developers.facebook.com/docs/reference/javascript/FB.getLoginStatus.

Code Solution so far...: If FB.login returns a response of unknown divert back to server-side login.

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

Hurdle #2: Are parameters passed appropriately?

If you have third party cookies unblocked, you might then encounter an error:

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

Despite setting cookie: true in the FB.init, sometimes params are still not passed. As stated in:

...you might need to manually pass in the signed_request parameter. Quick watch-out. Per Facebook docs (https://developers.facebook.com/docs/facebook-login/using-login-with-games), the signedRequest needs to have two components separated by a .. Not sure how, but I have gotten one without the . before. The separation is important, because it's the latter half that is a base64url coded JSON object containing the code information.

Code Solution so far...: Manually append signed_request parameter to callback 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)

Hurdle #3: Still nothing... still same error as #2

Maybe just me at this point?

Code Solution so far...: Go super pedantic, parse out the code from the signedRequest and append to callback 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"])

Hurdle #4: CSRF detected, but not for why you'd think

Now I've moved right into a brick wall. When I run the code as above, I get an error CSRF detected. There are a non-related reason one might get this error:

  • You can get this error if your Facebook app is in Dev mode and you are trying to login users live. In this case, FB doesn't allow any non-listed developers to log in. See first answer to this question: Rails + omniauth + facebook - csrf detected

But the problem in my case wasn't the above, it was that the code parameter was presented without a state parameter. Now, there have been answers saying that you can fix this by setting provider_ignores_state: true in the omniauth.rb config file, see second answer to question referenced above, BUT this is not a fix for me. Why? Because 1) I don't like turn things specifically designed to counter CSRF off and 2) it appears the config kicks in only for server-side log-in. Adding it simply didn't do anything for me.

Which means the bigger issue of the #3 solution was that it was trying to combine server-side login approach (takes code and state params) with client-side login approach (takes signed_request param).

Which means I'm back to the original question... how to pass the signed_request so that the client-side login works?


Since I've rambled on this much already, let me point out another error I've seen. This one has answers related to Facebook errors (Dealing with Oauth 2.0-facebook gem error 100: This authorization code has been used), but beyond that, I found something else that could trigger it.

As suggested in this tutorial (https://coderwall.com/p/bsfitw), you match the callback route via both get and post. But when I do this, my logger shows two requests to Facebook, the second obviously being blocked and triggering the error. (Also means that the first request did go through and the user is already authorized/ data is saved, whatever). My solution was to set route as so:

match 'auth/:provider/callback', to: 'signups#create_facebook', via: [:get]

解决方案

For those who still have this problem. Try not to use "localhost:3000" or whatever. Change /etc/hosts to a new url like

127.0.0.1 abc.com

Change facebook app setting at developers.facebook.com to point to the new url (instead of using localhost:3000, call it abc.com:3000)

and try the new login with js facebook login again. Should work fine!

这篇关于手动传递signed_pa​​rameters后的Facebook NoAuthorizationError的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆