iPhone应用程序的Facebook访问令牌服务器端验证

113

我正在开发一款基于与服务器通信的iPhone应用程序,并希望使用Facebook身份验证机制。

基本上,我认为应该像这样工作:

  1. 在我的iPhone应用中,用户使用他的电子邮件和密码登录Facebook。
  2. 用户允许访问相关Facebook应用程序的数据。
  3. 在成功登录后,我的iPhone应用程序接收访问令牌。
  4. 在与服务器的进一步通信中,我的iPhone应用程序应使用接收到的Facebook访问令牌(例如:在查询中)。
  5. 当我的服务器从iPhone应用程序接收到某个带访问令牌的查询时,它应该询问Facebook这个令牌是否有效(以及所属的用户),如果是,则服务器应假定用户已通过Facebook进行身份验证。

我的问题是:服务器如何询问Facebook给定的访问令牌是否有效? 我认为我应该检查该令牌是否对我的Facebook应用程序有效。

我尝试了许多我找到的Facebook查询图形API,但没有一个按照我预期的方式工作。 你能给我提供一些例子吗?


5
除非用户已经在Facebook应用程序中退出登录,否则可以直接将授权令牌发送到服务器(最好使用SSL)。通过图形API进行的“/me”查询是成功还是失败? - The Mad Gamer
你将收到Facebook的消息,提示你的令牌无效 :) - Jean-Luc Godard
1
我正在尝试做与你类似的事情。你从未标记过这个问题为已回答,你最终解决了这个问题吗? - tempy
当访问令牌过期时会发生什么?我们应该要求用户重新登录吗?我想了解在令牌过期后如何重新验证。 - debianmaster
@debianmaster 这取决于您的应用程序架构。如果您考虑“没有FB令牌-无法访问应用程序”的情况,那么是的,请注销用户。否则,您可以考虑“取消链接”逻辑,其中用户保持登录状态,但从Facebook接收的信息已从服务器/客户端中分离出来与其帐户无关。 - Yevhen Dubinin
8个回答

119

以下是验证用户访问令牌是否属于您的应用程序的两个步骤:

1) 生成应用访问令牌

(https://developers.facebook.com/docs/howtos/login/login-as-app/)

https://graph.facebook.com/oauth/access_token?
client_id=YOUR_APP_ID
&client_secret=YOUR_APP_SECRET
&grant_type=client_credentials

2) 调试用户访问令牌

(https://developers.facebook.com/docs/howtos/login/debugging-access-tokens/)

https://graph.facebook.com/debug_token?
input_token=INPUT_TOKEN
&access_token=ACCESS_TOKEN

其中INPUT_TOKEN是您想要验证的用户访问令牌,ACCESS_TOKEN是您从第一步中获得的应用程序令牌。

调试端点基本上会转储有关令牌的所有信息,因此它将响应类似于以下内容:

{
    data: {
        app_id: YOUR_APP_ID,
        is_valid: true,
        metadata: {
            sso: "iphone-safari"
        },
        application: YOUR_APP_NAMESPACE,
        user_id: USER_ID,
        issued_at: 1366236791,
        expires_at: 1371420791,
        scopes: [ ]
    }
}
如果那个令牌不是来自“你的应用”,则它将返回一个错误响应。

14
根据Facebook的说明,这是检查访问令牌的正确方法。但是,第一部分是可选的,因为您可以使用应用程序ID和密钥代替管理员或应用程序令牌。 - Brandon Zacharie
@BrandonZacharie 不知道你是怎么做的,我刚尝试了一下使用应用程序ID和密钥,但出现了“input_token参数必需”的错误。 - Johnny Z
8
@BrandonZacharie 您说得对,我混淆了输入令牌和访问令牌。要使用应用程序 ID 和密钥,我将其作为参数传递,并使用管道符作为分隔符:&access_token=APP_ID|APP_SECRET - Johnny Z
@JohnnyZ 哦天啊,这个参数格式太荒谬了... 他们为什么不接受 client_idclient_secret 呢... 这破坏了我库中所有的抽象... - Kolyunya
2
上面的链接现在是 https://developers.facebook.com/docs/facebook-login/access-tokens/debugging-and-error-handling - Chris Prince
显示剩余5条评论

115
更新:此回答似乎不安全,因为它没有首先验证令牌是否属于您的应用程序,请参见注释,原始答案如下:
我假设您已经拥有访问令牌。在这种情况下,验证访问令牌的最简单方法是发出以下请求。
https://graph.facebook.com/me?fields=id&access_token=@accesstoken

请将@accesstoken替换为您拥有的访问令牌。我将分解URL并解释每个部分。

我们正在发出一个图形API请求,该请求将返回JSON字符串格式的访问令牌所有者的Facebook用户ID。关键字“me”表示当前登录的用户或访问令牌的所有者。对于此请求,访问令牌是必填参数。

如果提供的访问令牌无效或已过期,则Facebook将返回某种错误消息。

对于有效的访问令牌,结果将类似于这样:

{
   "id": "ID_VALUE"
}

14
如果该用户提供的access_token属于另一个应用程序,那么这个请求会成功吗? - Yuriy Nemtsov
2
任何有效的用户访问令牌都可以使用(无论它属于哪个应用程序)。 - Robin
12
@Xiquid 这篇帖子并不是解决问题的答案,因为它没有验证访问令牌是否属于你的应用程序。 - Kolyunya
12
我不明白为什么这个答案得到了最多的投票!很明显这不是正确的解决方案。事实上,“海螺小队”的建议是正确的。debug_token端点用于查询有关令牌本身的信息,并通过这种方式您可以验证该令牌是否属于特定用户ID和特定应用程序ID! - Alex Ntousias
4
是的,这个答案是不正确的。如果你以这种方式验证访问令牌,有人可以从另一个应用程序获取访问令牌,并使用它来进行身份验证。 - Jonathan
显示剩余10条评论

11

我怎样才能获取其他Facebook商家的评价?我需要做些什么? - Maneesh Rao

6
在 Facebook 的最新版本 (2.2) 中,你可以这样做:

https://developers.facebook.com/docs/graph-api/reference/v2.2/debug_token

示例输出:
{
    "data": {
        "app_id": "THE APP ID", 
        "application": "APP NAME", 
        "expires_at": 1427245200, 
        "is_valid": true, 
        "scopes": [
        "public_profile", 
        "basic_info", 
        "read_stream", 
        "email", 
        "publish_actions", 
        "read_friendlists", 
        "user_birthday", 
        "user_hometown", 
        "user_location", 
        "user_likes", 
        "user_photos", 
        "user_videos", 
        "user_friends", 
        "user_posts"
        ], 
        "user_id": "THE USER ID"
    }
}

这是否意味着每次请求都必须调用此fb端点?难道没有更好的方法吗? - Jdruwe
这个可以工作,但需要访问令牌。访问令牌可以使用“小螃蟹塞巴斯蒂安”的答案生成,或者我们可以简单地使用appid | appsecret。更多信息请参见https://developers.facebook.com/docs/facebook-login/access-tokens#apptokens。 - krishnan
以下是这个的一个例子用法:https://dev59.com/EGsz5IYBdhLWcg3wDjto#16947027 - rogerdpack

2
这是仅需一个请求来验证用户令牌的唯一安全方法:
https://graph.facebook.com/debug_token?input_token={token-to-inspect}&access_token={app_id}|{app_secret}

注意,上述URL中的符号“|”不用作OR,而是分隔符,在填写其他字段之后必须存在。
响应将是JSON格式的,如下所示:
{
    data: {
        app_id: {app_id},
        application: {app_name},
        expires_at: {some_number},
        is_valid: {true|false}
        scopes: {array_of_permissions},
        user_id: {user_id}
    }
}

参考:https://developers.facebook.com/docs/facebook-login/access-tokens/#apptokens (上述方法在本节底部提到)

还有一种只需要一个请求的安全方式:https://dev59.com/EGsz5IYBdhLWcg3wDjto#36555287 - rogerdpack

2
如果用户传递给您一个他们声称是自己的Facebook UID,并且您想检查它是否真实,这是一个Python函数,可以根据他们的访问令牌进行验证(Robin Jome答案的实现):
def verify_facebook_id(id, access_token):
    import requests
    import simplejson
    params = {'fields': 'id', 'access_token': access_token}
    text = requests.get("https://graph.facebook.com/me", params=params).text
    json = simplejson.loads(text)
    response_id = json["id"]
    return response_id == id

很遗憾,这并不能验证该令牌是否是“为您的应用程序”生成的... - rogerdpack

2
private function facebookRequestMe($access_token)
{
    include_once "facebook.php";

    $facebook = new Facebook(array(
        "appId" => "your_application_id",
        "secret" => "your_application_secret"
    ));
    $facebook->setAccessToken($access_token);
    return $facebook->api("/me", "GET");
}

您可以从GitHub下载Facebook PHP SDK。

-1

除了访问令牌之外,Facebook 还会发送一个 "expires_in" 参数,这是一个偏移值。使用它来计算什么时候访问令牌将作为 NSDate 过期。然后,在您需要进行请求时,请将当前日期与过期日期进行比较。

还要尝试检查 Facebook 发回的状态代码和响应字符串。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接