如果已经授权的用户现在需要更多权限,如何在canvas应用程序中的signed_request中获取访问令牌?

时间:2012-01-13 12:54:37

标签: php facebook-graph-api facebook facebook-canvas

让我们假设画布应用程序存在以下情况:

i)第1天:   - 创建需要的Facebook应用程序    read_stream,publish_stream,offline_access权限。当一个    用户第一次来到应用,authorize来电重定向用户    到权限允许/拒绝屏幕,以及用户允许时    将用户重定向回画布URL。

画布网址在其请求中的已签名请求中具有access_token    然后可用于运行应用程序的参数。

下次访问该应用的同一用户无需使用权限对话框    时间,因为如果用户有,则signed_request包含acess_token    过去授权该应用程序。

代码如下:

if(access_token received from signed request)
// do something with user information
else
// redirect user for authorization flow

ii)第2天: - 现在,假设我想在我的列表中添加一个权限user_birthday read_stream,publish_stream,offline_access,user_birthday` 现在,以下逻辑将出现问题

  if(access_token received from signed request)
    // do something with user information  <-- the access_token does not have new permission
    else
    // redirect user for authorization flow

如何通过API调用有效地解决此附加权限添加问题 影响应用程序的性能? 我不想使用类似的东西:

https://graph.facebook.com/me/permissions?access_token=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

每次加载应用程序时都要检查与令牌相关的权限。

更新

分享一个好方法: 存储权限集以及接收它的access_token。 例如。如果当前权限是“basic_details-birthday-publish”(让我们称之为1), 将access_token和权限集存储为

user  | access_token  | perm_set
Dhruv      sdfsdfsdf       1

现在,在您的设置中,每当您需要申请新权限时,请创建一个新的权限集“basic_details-birthday-publish-checkins”(让我们称之为2),

然后,您需要仅为具有perm_set = 1的访问令牌的用户显示权限对话框,而不是对已经拥有perm_set = 2的用户显示权限对话框,这将消除使用“/ me”检查每个用户的access_token的需要/ permissions“api。

8 个答案:

答案 0 :(得分:5)

这将是一个两步过程:

  1. 通过向图表路径“/ me / permissions”发出请求,检查用户是否授予您所有必需的权限

  2. 如果用户未授予您所有必需的权限,则需要执行通常的允许/拒绝过程,但这次将新权限添加到“scope”参数中。

    < / LI>

    编辑_:我知道验证权限的唯一可靠方法是调用/ me / permissions。

答案 1 :(得分:3)

嗯,最有效的解决方案需要@Jeff建议加上使用Real-time API 第1步:创建权限表,以便在用户第一次“连接”到您的应用时存储用户权限。
第2步:订阅权限对象,例如:

<?php
require '../src/facebook.php';

$facebook = new Facebook(array(
  'appId'  => 'APP_ID',
  'secret' => 'APP_SECRET',
));

$app = get_app_access_token("APP_ID", "APP_SECRET");
parse_str($app);

$realtime_params = array(
    'object'=>'permissions',
    'fields'=>'read_stream,publish_stream', // most recent permissions required by your app
    'callback_url'=>'CALLBACK_URL_HERE',
    'verify_token'=>'STRING_THAT_SHOULD_BE_PRESENT_IN_THE_CALLBACK_PAGE_TOO',
    'access_token'=>$access_token
);

try {
$res = $facebook->api("/APP_ID/subscriptions", "post", $realtime_params);
} catch (FacebookApiException $e) {
echo '<pre>'.htmlspecialchars(print_r($e, true)).'</pre>';
}
function get_app_access_token($id,$secret) { 
    $token_url =    "https://graph.facebook.com/oauth/access_token?" .
                    "client_id=" . $id .
                    "&client_secret=" . $secret .
                    "&grant_type=client_credentials";
    return file_get_contents($token_url);
}

Real-time Updates文档中有关此内容的更多信息。

第3步:如果用户撤消了其中一项权限(例如,删除了publish_stream权限),您的回调页应处理Facebook发送的帖子请求;在这种情况下,Facebook将向您发送类似的内容(解码请求后,请参阅here):

Array
(
    [object] => permissions
    [entry] => Array
        (
            [0] => Array
                (
                    [uid] => 100003355152933
                    [id] => 100003355152933
                    [time] => 1327005647
                    [changed_fields] => Array
                        (
                            [0] => publish_stream
                        )

                )

        )

)

无论改变了什么,我都会将上述请求用作触发器,查询/user_id/permissions连接并更新权限表。

现在你有两种情况:

if(access_token received from signed request)
    if(permissions from table are full)
        // do something with user information
    else
        // ask for missing permission and update permissions table
else
    // redirect user for authorization flow
    // upon full authorization, save to the permissions table too

显然,也应该使用其他答案中所说的内容。您应该始终使用“try ... catch”子句并检查与权限相关的错误并采取相应措施!

答案 2 :(得分:2)

你有三个选择,其中一个是你已经说过你不想做的选择。

  1. 检查me/permissions并循环查看是否所有这些内容仍然存在。

  2. 尝试/捕获每个API调用并观察收到的错误(请参阅http://fbdevwiki.com/wiki/Error_codes)以查看它是否为#10 API_EC_PERMISSION_DENIED。如果是,请再次询问用户权限。

  3. 编写您的应用,使其向后兼容旧的权限集,因此只有已授予新权限的用户才会显示其中的新功能。当然,您需要尝试/捕获每个API调用,以找出您需要隐藏/显示的应用程序的哪些部分。

答案 3 :(得分:1)

首先,我会说明显而已。您应该使用/me/permissions端点。这是确定访问令牌是否有效并具有您需要/想要的所有权限的唯一方法。既然你说每次加载应用程序都需要一个没有达到此端点的解决方案,我会继续前进。

我能想到不检查/me/permissions API调用的唯一方法是使用将user_id映射到用户权限的简单表来跟踪您自己服务器上的权限。授权新用户时,可以在数据库表中为该fb用户ID和他们授权的权限列表添加一行。现在当他们回来时,你可以获得signed_request并在你的表中查找他们是否拥有你想要的所有权限。如果他们不这样做,则提示他们授权其他权限,并在他们授予您这些权限时更新您的表。

由于您已经要求使用offline_access,我假设您无论如何都要在某处存储访问令牌,因此添加另一个表以获取访问令牌的权限列表似乎不会带来太大的额外负担

此设计存在一些明显的缺陷(与FB不一致),但如果您的主要目标是避免/me/permissions端点,那么这应该对您有用。

答案 4 :(得分:1)

不要忘记您也可以使用javascript SDK来提示权限。 javascript SDK实际上是内联的。您可以使用所需的权限参数调用“登录”功能,如果它们已被授予,则不会发生任何事情。

正如其他人建议的那样,您可以查询/ me / permissions图表,但使用javascript api方法获取信息。因此,如果您不想存储用户授予的权限,并订阅实时更新API以确保它们保持最新,则可以使用javascript api从客户端进行内联操作。

你几乎消除了你的服务器扮演任何角色并通过javascript直接将用户链接到Facebook。 Facebook实际上在客户端进行了一些缓存,因此呼叫可能是即时的。

这是一篇关于提示缺少权限的Facebook博文。 https://developers.facebook.com/blog/post/576/

答案 5 :(得分:0)

此处的所有答案都基于较旧的facebook auth系统,其中,当没有有效的signed_request参数时,您将用户重定向到oauth url,scope参数包含您需要的权限。

如果没有请求脱机访问权限,则没有问题,因为每个用户访问令牌在两小时内都将无效,因此在使用新权限更改scope参数两小时后,每次新访问都将重定向到oauth具有新范围的页面,因此Facebook将正确处理它。

由于您已经获得了脱机权限并且您需要它,因此用户的访问权限不会轻易被取消(如果只有用户更改密码或停用您的应用程序),前面的解决方案将无法正常工作,

我接受检查图api调用中的权限错误,这是一种检查用户不允许您提出要求的方法,然后重定向用户让他或她获得您的权限。这是可以接受的,但是没必要

因为现在,您可以在Facebook应用设置页面中提供所需的权限,更具体地说是

转到https://developers.facebook.com/

并选择您的应用。

点击设置 - &gt;左侧菜单中的Auth Dialog选项卡。 并选择您必须的权限,这将允许所有用户肯定,将来到您的页面具有所需的权限,

但是,你不能在这里获得任何扩展许可。

因此,对您的问题唯一可能的答案是,一次删除所有访问权限,因为这样可以将所有返回用户重定向到新权限对话框。

但是这个解决方案将为您提供有关获取用户群信息的帮助, 要克服此问题,您只能在用户访问您的网页时触发此操作,因此在删除其访问令牌后,用户可能会重新访问您的网页。但是你必须为每个用户保留一点额外的东西,并保持他们受到这种访问令牌删除操作。如果用户没有接受此操作并访问您的应用程序,只需删除访问令牌并将用户重定向到具有新权限的oauth页面,如果用户已经这样做,那么此类事情就没有问题。

所以我的答案是上面的选择。但是解决这个问题最难和最优雅的方法是,只有当用户与您的应用互动时才会要求权限,以便使用您需要我们谈论的权限的应用功能。这样,oauth对话框的CTR率会上升,因为你不会让你的用户害怕你要求的初始权限的长度。用户将更多地了解如何使用您的应用。每当他们需要在你的应用程序中做精彩的事情时,你就可以请求一个很好的许可。

祝你好运

答案 6 :(得分:0)

实施建议。

将权限集与接收它的access_token一起存储。 例如。如果当前权限是“basic_details-birthday-publish”(让我们称之为1), 将access_token和权限集存储为

user  | access_token  | perm_set
Dhruv      sdfsdfsdf       1

现在,在您的设置中,每当您需要申请新权限时,请创建一个新的权限集“basic_details-birthday-publish-checkins”(让我们称之为2),

然后,您需要仅为具有perm_set = 1的访问令牌的用户显示权限对话框,而不是对已经拥有perm_set = 2的用户显示权限对话框,这将消除使用“/ me”检查每个用户的access_token的需要/ permissions“api。

答案 7 :(得分:-1)

$facebook = new Facebook(array(
                'appId' => 'xxxxxx',
                'secret' => 'xxxxx',
                'cookie' => true,
            ));
$code = @$_REQUEST["code"];//only get after log in into the app
if(empty($code)) 
{
$dialog_url     = "http://www.facebook.com/dialog/oauth?client_id=" 
                . $app_id . "&redirect_uri=" .  urlencode($canvas_page_url)."&scope=email,read_requests,offline_access,read_mailbox,user_relationships,user_likes,user_online_presence,user_activities,user_status,user_groups,manage_pages,friends_status,read_stream,friends_photos,publish_stream";
 echo("<script> top.location.href='" . $dialog_url . "'</script>");
}
 $token_url         = "https://graph.facebook.com/oauth/access_token?client_id="
                . $app_id . "&redirect_uri=" . urlencode($canvas_page) . "&client_secret="
                . $app_secret . "&code=" . $code;
$access_token   = @file_get_contents($token_url);

尝试上面的代码并重新加载应用程序,然后会弹出一个窗口以获取您添加的额外权限。