检查Facebook用户是否在没有PHP SDK的情况下登录

时间:2015-01-26 09:12:21

标签: php facebook facebook-graph-api curl facebook-php-sdk

我试图通过自编代码模拟Facebook登录工作流程(即不使用Facebook PHP SDK),根据Facebook文档,这应该是可能的并且非常简单:

  

“使用我们的SDK的应用可以检查某人是否已登录   使用内置函数。所有其他应用程序必须创建自己的方式   当一个人登录时存储“

https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow/v2.2

我的主要动机是Facebook和SDK的频繁更改令人沮丧,并敦促我使用自编写的库迁移到本机HTTP请求。

使用SDK时,进程应该是(这是以前的版本):

$facebook = new Facebook(array(
    'appId'     => MY_APP_ID,
    'secret'    => MY_APP_SECRET,
    ));
$this_user_facebook_id = $facebook->getUser(); // Get User ID
if($this_user_facebook_id > '0')
    {
    try
        {
        $user_access_token = $facebook->getAccessToken();
        // do whatever you like
        }
    }
catch(FacebookApiException $e)
    {
    print_r($e);
    $this_user_facebook_id = NULL;
    }

我想要遵循的过程是:

问题是我在这个阶段被放弃了:我试图阅读Facebook重定向标题,直到意识到Facebook实际上使用元标记重定向用户:

<meta http-equiv="refresh" content="0;url=https://www.facebook.com/login.php?skip_api_login=1&amp;api_key=............ ------LONG FACEBOOK URL ------->

问题是我找不到原生网址,即即使用户确实重定向到http://MY_APP_REDIRECT_URL/?code=

我试图读取CURL标题,但那里什么都没有。我还尝试生成APP访问令牌并通过它查询用户访问令牌(失败)。

任何线索?任何想法如何生成本机HTTP图谱API请求,导致查询用户access_token?我在网上试图解决这个问题已经有三天了,而且Facebook文档也没那么有用。

1 个答案:

答案 0 :(得分:3)

  

“使用我们的SDK的应用可以检查是否有人已使用内置函数登录。当一个人登录时,所有其他应用程序必须创建自己的存储方式“

实际上链接到

https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow/v2.2#token

  

存储访问令牌和登录状态

     

在流程的这一点上,您有人经过身份验证和记录   in。您的应用已准备好代表他们进行API调用。在做之前   所以,它应该存储访问令牌和登录状态   使用该应用程序的人。

     

存储访问令牌

     

您的应用收到访问令牌后   在上一步中,令牌应该存储,以便所有人都可以使用   应用程序的一部分,当它进行API调用时。没有具体的过程   在这里,不过一般来说,如果您正在构建一个Web应用程序,最好是   将标记添加为会话变量以标识该浏览器会话   与特定的人,如果您正在构建本机桌面或   移动应用,那么您应该使用您的应用可用的数据存储。   此外,应用程序应将令牌与数据库一起存储在数据库中   user_id来识别它。

     

请参阅我们关于访问权限中访问令牌大小的说明   令牌文件。

     

跟踪登录状态

     

同样,您的应用应该存储一个人的登录信息   status,有助于避免对Login进行额外调用   对话。无论您选择何种程序,请修改您的登录状态   检查以解释它。

所以他们说这是因为他们用于例如JS SDK,会话已经由Facebook存储,因此获取登录状态可以动态完成,而不是手动方式。

我发现你也在使用旧的PHP SDK

$this_user_facebook_id = $facebook->getUser();

如果您在源https://github.com/facebookarchive/facebook-php-sdk/blob/master/src/base_facebook.php中检查此功能,您将看到它的作用是检查是否设置了用户,如果没有从可用数据中检查用户。这里的可用数据按此顺序

  • 任何signed requests
  • 授权码
  • 然后回到存储用户的任何持久性商店。

如果没有设置,则没有有效用户。

检查类似服务器的最简单方法是为用户存储一个id和访问令牌(当他们第一次授权应用程序时)

  1. 用户通过对话框登录
  2. 使用ID /会话(或密码,但您的应用有效)存储用户并存储令牌
  3. 当下一个应用识别会话时(无论是您设置的cookie管理系统还是简单的用户/通行证设置),从数据库中检索令牌并对其进行调试https://developers.facebook.com/docs/graph-api/reference/v2.2/debug_token
    4A。令牌有效吗?是的,不要调用登录对话框
    4B。是令牌invald,Invoke对话框
  4. 调试令牌调用如何工作

    https://graph.facebook.com/debug_token?input_token=USER_ACCESS_TOKEN_STORED_IN_DB&access_token=APP_TOKEN

    响应

    {
      "data": {
        "app_id": "APP_ID", 
        "application": "APP_NAME", 
        "expires_at": 1422295200, 
        "is_valid": true, 
        "scopes": [
          "public_profile", 
          "read_mailbox", 
          "read_page_mailboxes", 
          "ads_management", 
          "ads_read", 
          "manage_pages", 
          "publish_actions"
        ], 
        "user_id": "USER_ID"
      }
    }
    

    如果令牌无效,则响应中也会返回错误,is_valid设置为false。

    {
      "data": {
        "app_id": "APP_ID", 
        "application": "AnyLeepingTest", 
        "error": {
          "code": 190, 
          "message": "Error validating access token: Session has expired on Jan 9, 2015 7:00pm. The current time is Jan 26, 2015 8:22am.", 
          "subcode": 463
        }, 
        "expires_at": 1420858800, 
        "is_valid": false, 
        "profile_id": "PROFILE_ID", 
        "scopes": [
          "public_profile", 
          "read_mailbox", 
          "read_page_mailboxes", 
          "ads_management", 
          "ads_read", 
          "manage_pages", 
          "publish_actions"
        ], 
        "user_id": "USER_ID"
      }
    }
    

    因此,只要您存储从用户检索到的最后一个访问令牌,您就可以判断他的用户是否已登录您的应用。


    如果您不存储令牌并想要确定登录状态,那么这有点复杂。

    您可以在cURL中自动生成的唯一令牌(无需用户交互)是应用程序访问令牌。

    用户互动不仅仅是Facebook标准。它实际上已在OAuth规范中声明

    https://tools.ietf.org/html/rfc6749

      

    在启动协议之前,客户端注册      授权服务器。客户注册的方式      与授权服务器超出了这个范围      规范,但通常涉及最终用户与HTML的交互      报名表。

    Facebook内部为开发人员资源管理器工具和一些原生应用程序生成用户访问权限,但这取决于Facebook和用户之间的信任。由于我们是第三方开发者,Facebook不向开发人员提供信任级别。

    现在获取更多技术信息,说明为什么这不能在大规模设置中起作用

    Server Flow

    这是所有服务器端流程的外观,SDK或没有SDK。 第一,第三和第四条腿都可以在后台完成。第二站

      

    用户接受对话框并发送至redirect_uri,其中包含code参数

    关注的是什么,基本上当用户点击对话框中的按钮时,会发出POST请求

    https://www.facebook.com/v2.2/dialog/oauth/read

    fb_dtsg:FB_DTSG
    app_id:APP_ID
    redirect_uri:https://developers.facebook.com/tools/explorer/callback
    display:page
    access_token:
    sdk:
    from_post:1
    public_info_nux:1
    private:
    login:
    read:public_profile,baseline
    write:
    readwrite:
    extended:
    social_confirm:
    confirm:
    seen_scopes:public_profile,baseline
    auth_type:
    auth_token:
    auth_nonce:
    default_audience:
    ref:Default
    return_format:code
    domain:
    sso_device:
    sheet_name:initial
    __CONFIRM__:1
    __user:13608786
    __a:1
    __dyn:...
    __req:4
    ttstamp:...
    __rev:...
    

    从上面可以看出,应该注意的是,要使此POST请求在cURL中工作,您需要fb_dtsg用户来防御CSRF攻击,这样您就无法获得此

    在对令牌的后续请求中(假设,没有要求其他权限),您将不需要fb_dtsg令牌,但仍然必须使用

    来命中此端点

    https://www.facebook.com/dialog/oauth?client_id=MY_APP_ID&redirect_uri=FACEBOOK_REDIRECT_URL&scope=MY_APPROVED_SCOPE

    在这里Facebook检查哪个用户正在访问此端点,唯一可行的方法是使用有效的cookie

    • datr
    • lu
    • c_user
    • fr
    • XS
    • 取值
    • 行为

    REF:Facebook Ireland Audit Review Report_21 Sept 2012

    现在假设您可以获得fb_dtsg和有效的cookie会话数据,使用您的cURL请求,您仍然必须通过发送用户代理来模拟浏览器,因为Facebook会在抓取网站的计算机上进行操作。

    所以你的cURL请求实际上更符合

    curl 'https://www.facebook.com/v2.2/dialog/oauth/read' -H 'origin: https://www.facebook.com' -H 'accept-encoding: gzip, deflate' -H 'accept-language: en-US,en;q=0.8' -H 'user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.99 Safari/537.36' -H 'content-type: application/x-www-form-urlencoded' -H 'accept: */*' -H 'referer: https://www.facebook.com/v2.2/dialog/oauth?response_type=code&client_id=819244098116110&redirect_uri=FACEBOOK_REDIRECT_URL' -H 'cookie: datr=...; lu=...; c_user=...; fr=...; xs=...; csm=2; s=...; wd=1408x472; act=...' --data 'fb_dtsg=...&app_id=819244098116110&redirect_uri=FACEBOOK_REDIRECT_URL&display=page&access_token=&sdk=&from_post=1&public_info_nux=1&private=&login=&read=public_profile%2Cbaseline&write=&readwrite=&extended=&social_confirm=&confirm=&seen_scopes=public_profile%2Cbaseline&auth_type=&auth_token=&auth_nonce=&default_audience=&ref=Default&return_format=code&domain=&sso_device=&sheet_name=initial&__CONFIRM__=1&__user=13608786&__a=1&__dyn=...&__req=4&ttstamp=...&__rev=...' --compressed

    之后,您将收到

    的回复

    for (;;);{"__ar":1,"payload":null,"jsmods":{"require":[["ServerRedirect","redirectPageTo",[],["https:FACEBOOK_REDIRECT_URL?code=CODE_PARAM#_=_",true]]]},"js":["J93Wm"],"bootloadable":{},"resource_map":{"J93Wm":{"type":"js","crossOrigin":1,"src":"https:\/\/fbstatic-a.akamaihd.net\/rsrc.php\/v2\/yg\/r\/IZE34GLft38.js"}},"ixData":{},"lid":"0"}

    所以是的,浏览器模拟很棘手,并且取决于许多因素和信任级别,大多数用户都无法提供给您,因为基本上所有这些都可以使用,您需要用户的密码。

    以上所有内容都不言而喻,这只是理论工作,展示了如何在没有用户启动流程的情况下进行操作。正如之前在评论中所提到的,这既反对Facebook TOS和Facebook开发者政策,所以我认为危及您的开发者帐户,个人帐户,应用程序和客户的风险超过了不必处理用户交互的好处。

    也许尝试发送拉取请求以根据自己的喜好更新PHP SDK? https://github.com/facebook/facebook-php-sdk-v4/pulls:)