SalesForce canvas 应用程序 oauth 网络服务器流程,用户交互最少

SalesForce canvas app oauth web server flow with minimal user interaction

所以我正在权衡 SalesForce Canvas 应用程序的不同身份验证机制的 pros/cons。

首先,介绍一下背景。我有一个现有的 Web 应用程序 - 我们称它为 "myapp"。我设置了一个包含 VisualForce 页面的 VisualForce 选项卡,该页面通过以下方法嵌入了我的 canvas 应用程序:

<apex:page>
    <apex:canvasApp applicationName="___________" />
</apex:page>

我首先通过签名请求方法实现了访问,这很棒,因为用户只需在第一次访问时接受我的应用程序的权限,随后尝试访问我的 canvas 应用程序可以直接跳转到我的应用主页。

阅读 this article 关于为不同的 SalesForce 版本打包 canvas 应用程序,签名请求方法有一个限制:

Most typical Group and Professional Edition customers are not going tobe able to use your Signed Request Connected App unless they upgrade to EE or higher or purchase these features as an add-on.

所以我决定切换到 oauth 工作流程。

查看 user agent oauth flow documentation,它说:

The user must always approve access for this authentication flow. After approving access, the application receives the callback from Salesforce.

这也是不可取的,但是 the web server oauth flow 没有该要求 - 一旦用户接受了应用程序的权限要求,就不需要再次提示他们这样做。它还使诸如在 myapp 的登录页面上添加 "Login with SalesForce" 选项之类的操作变得非常容易。

所以我设置了网络服务器 oauth 流程,并且一切正常,作为一个额外的好处,我在登录页面添加了一个 "Login with SalesForce" 选项 - 太棒了。

下一步是在 VisualForce 选项卡中设置 canvas 应用程序以启动 Web 服务器 oauth 流程。

我要解决的问题:

我想使用网络服务器 oauth 流程从该 VisualForce 选项卡访问 myapp 的主页,在此过程中尽可能少的用户交互。

基本设置

为了启动 oauth 流程,我设置了一个 URL,其中包含以下逻辑,以便轻松创建从其他地方启动流程的链接。以下每个示例都使用了它,并通过指向 /salesforce/oauth/......

的链接引用
// Allow links to this page to specify "state" and "prompt" paramaters.
$state  = isset($_GET['state'])  ? $_GET['state']  : 'login';
$prompt = isset($_GET['prompt']) ? $_GET['prompt'] : '';

// Canvas app contextual information provides the right SalesForce endpoint domain, so provide a way for that to be passed in here, or fallback to standard login.salesforce.com for other workflows.
$authDomain = isset($_GET['authDomain']) ? $_GET['authDomain'] : 'https://login.salesforce.com/services/oauth2/authorize';

$url = $authDomain.'?'.http_build_query(array(
    'response_type' => 'code',
    'client_id'     => 'XXXXXXX_MY_APP_CLIENT_ID',
    'redirect_uri'  => 'https://'.$_SERVER['HTTP_HOST'].'/salesforce/authorize/',
    'state'         => $state,
    'prompt'        => $prompt,
));

header('Location: '.$url);
die;

第 1 次尝试失败

使用 javascript canvas sdk,重定向 canvas 应用程序以启动我的网络服务器 oauth 流程:

location.href = '/salesforce/oauth?authUrl='+encodeURIComponent(Sfdc.canvas.oauth.loginUrl())+'&state=canvas';

我运行用这种方法遇到了两个问题:

  1. canvas 应用丢失了其 URL 中 #query 片段提供的上下文信息。
  2. 具有 accept/decline 权限的 SalesForce 页面的
  3. X-Frame-Options header 阻止它在 iframe 中显示,即使在 SalesForce 域中 .

我觉得如果可以克服这些问题,这将是实现我的目标的最佳方式。

我实际上做了一个实验,通过在我的 canvas 应用程序中的另一个 iframe 中加载 URL 来解决问题 #1,如果我已经接受了完美运行的 myapps 权限要求,然而,当弹出权限屏幕并且整个过程未能完成时,我仍然遇到问题 #2。

当前解决方案

我已经让最初的 canvas 应用程序页面包含一个单击按钮,它会在新的 window 中打开网络服务器 oauth 流程,并在其中成功完成。完成后,canvas 应用程序 iframe 被重定向到我的应用程序主页。

我对此很不满意,因为每次我点击我的 VisualForce 选项卡时,都会有一个步骤要求用户点击一个按钮,然后会弹出一个新的 window 到 运行 oauth 工作流程。如果用户过去已经接受了应用程序权限,它会在没有额外用户交互的情况下自动关闭,或者提示他们接受,如果他们还没有接受,然后自行关闭。

如果我坚持使用这个解决方案,那还不是世界末日 - 我们会将那个按钮变成一个闪屏,里面有一些营销废话,还有一个令人讨厌的大 "Continue to MyApp" 按钮。

问题(...终于)

有什么方法可以删除每次加载 canvas 应用程序时单击按钮的必要步骤,但在此处继续使用网络服务器 oauth 流程? (记住我不想使用用户代理 oauth 流程,因为它有一个类似的要求,即每次用户访问它时都要接受权限)。

当 canvas 应用程序嵌入销售人员帐户或联系人屏幕时,这个额外的步骤特别烦人 - 因为它会阻止我的应用程序加载并向我的用户显示数据,直到用户单击按钮.

要么我不明白,要么这很简单。您需要使用 oAuth immediate 参数:

immediate — Determines whether the user should be prompted for login and approval. This parameter is optional. The value must be true or false if specified. Default value is false. Note the following: If set to true, and if the user is currently logged in and has previously approved the client_id, Salesforce skips the approval step. If set to true and the user is not logged in or has not previously approved the client, Salesforce immediately terminates with the immediate_unsuccessful error code.

来源:1, 2

唯一的问题是最后一部分:如果用户尚未授权您的应用程序,您将收到错误消息。根据我使用 oAuth 的经验,使用 Javascript 到 运行 来自客户端浏览器本身的请求确实更容易。您可以触发 immediate = true 请求,并紧随其后 immediate = false 以防第一个请求失败。然后,您通过创建第三个请求将 access_token 发送到您的应用程序 – 到您自己的服务器。