【问题标题】:How to get access_token in signed_request in canvas app, if an already authorized user needs more permissions now?如果已经授权的用户现在需要更多权限,如何在 canvas 应用程序的 signed_request 中获取 access_token?
【发布时间】:2012-02-09 16:12:01
【问题描述】:

让我们假设画布应用的情况如下:

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

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

下次访问应用的同一用户不需要权限对话框 时间,因为 signed_request 包含 access_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。

【问题讨论】:

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


    【解决方案1】:

    这将是一个两步过程:

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

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

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

    【讨论】:

    • Dhruv 说他不想做那个特别的检查。
    • 似乎这就是您将其包含在答案中的原因?
    • 大声笑,只是反复强调这是最好的方法。正如你所看到的,我说我的三个之一是他说他不想做的那个。 :)
    【解决方案2】:

    嗯,最有效的解决方案需要 @Jeff 建议的内容以及使用实时 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”子句并检查与权限相关的错误并采取行动!

    【讨论】:

    • @BjörnKaiser,谢谢。补充一点,在使用实时更新时,您很可能需要将任务排队,这不是 PHP 最强大的功能!
    【解决方案3】:

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

    1. 检查me/permissions 并循环查看它们是否仍然存在。

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

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

    【讨论】:

      【解决方案4】:

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

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

      由于您已经在请求offline_access,我假设您无论如何都将访问令牌存储在某个地方,因此为访问令牌的权限列表添加另一个表似乎不会造成太大的额外负担.

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

      【讨论】:

        【解决方案5】:

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

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

        您几乎消除了您的服务器扮演任何角色并通过 javascript 将用户直接链接到 Facebook。 Facebook 实际上在客户端做了一些缓存,所以调用可能是即时的。

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

        【讨论】:

          【解决方案6】:

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

          如果没有请求离线访问权限,那么没有问题,因为每个用户访问令牌都会在两个小时内失效,所以在用新权限更改范围参数两个小时后,每次新访问都会重定向到 oauth具有新范围的页面,因此 facebook 将正确处理它。

          既然你已经取了离线权限并且你需要它,那么用户的accesstokens不会轻易失效(如果只是用户更改密码,或者停用你的应用程序),前面的解决方案将无法正常工作,

          我接受在图形 api 调用中检查权限错误是一种检查用户是否不允许您执行您所要求的操作然后重定向用户以让他或她向您保证您的权限的方法。可以接受,但没必要

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

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

          然后选择您的应用。

          单击左侧菜单中的设置 -> Auth Dialog 选项卡。 并选择您必须的权限,这将允许所有用户肯定会以所需的权限访问您的页面,

          但是,您不能在此处强制执行任何扩展权限。

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

          但此解决方案将帮助您获取有关您的用户群的信息, 为了克服这个问题,你只能在用户访问你的页面时触发这个,所以在删除他或她的访问令牌后,用户可能会重新访问你的页面。但是您必须为每个用户保留一个额外的位,以确保他们是否受到此访问令牌删除操作的影响。如果用户没有进行这个操作,访问了你的应用,只需删除访问令牌,并将用户重定向到具有新权限的oauth页面,如果用户已经这样做了,那么这种事情没有问题。

          所以我的答案是上述选择。但是解决这个问题的最困难和最优雅的方法是,只在用户与您的应用交互时才请求权限,以使用您的应用的需要我们讨论的权限的功能。这样,oauth 对话 CTR 率就会上升,因为您不会让用户害怕您请求的初始权限的长度。用户将更加了解使用您的应用程序。每当他们需要在您的应用中做一些奇妙的事情时,您都可以请求获得奇妙的许可。

          祝你好运

          【讨论】:

            【解决方案7】:

            一个实施建议。

            将权限集与接收它的 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】:
              $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);
              

              尝试使用上述代码并重新加载应用程序,然后它将显示一个弹出窗口以访问您添加的额外权限。

              【讨论】:

              • 这个答案不正确,根本没有使用signed_request。
              • 永远不会!因为我目前在我的应用程序中使用此代码并且它运行良好。可以通过这种方式使用应用程序访问令牌生成而不使用签名请求方法。更多确认请参见developers.facebook.com/blog/post/480
              • 此代码将使应用程序请求访问令牌,并在用户每次访问应用程序时通过 0Auth2.0 身份验证流程。使用signed_request,这不是必需的,因为过去已经验证了信息的用户,在signed_request 中获取用户信息和access_token 等信息。在这里阅读更多:developers.facebook.com/docs/authentication/signed_request
              • 在您的权限中进行更改后,您应该必须获得与权限相对应的适当访问令牌。即,每次您更改权限时,您的访问令牌也会被修改。如果我们将访问令牌存储在数据库中,则没有每次都需要。谢谢你的信息。
              猜你喜欢
              • 2020-02-17
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2012-05-30
              • 1970-01-01
              • 1970-01-01
              • 2019-11-05
              • 2013-10-07
              相关资源
              最近更新 更多