Php 谷歌应用市场SSO:离线访问

Php 谷歌应用市场SSO:离线访问,php,single-sign-on,google-apps,google-apps-marketplace,Php,Single Sign On,Google Apps,Google Apps Marketplace,我们的应用程序广泛地与谷歌服务(如邮件、联系人、日历等)集成。对于所有这些谷歌服务,我们需要永久访问用户的数据,而无需在每次需要从谷歌获取数据时请求用户许可。当我们通过谷歌IMAP同步联系人、日历或访问邮件时,即时访问用户数据非常重要。 我们还通过单点登录(SSO)从任何谷歌服务访问我们的应用程序。现在我们有麻烦了。 我们要求安装我们的应用程序的用户“离线”访问他们的数据。因此,当我们运行同步脚本等时,我们可以立即访问他们的数据。 用户首次授予访问我们的应用程序的权限时(通过SSO,当用户单击我

我们的应用程序广泛地与谷歌服务(如邮件、联系人、日历等)集成。对于所有这些谷歌服务,我们需要永久访问用户的数据,而无需在每次需要从谷歌获取数据时请求用户许可。当我们通过谷歌IMAP同步联系人、日历或访问邮件时,即时访问用户数据非常重要。 我们还通过单点登录(SSO)从任何谷歌服务访问我们的应用程序。现在我们有麻烦了。 我们要求安装我们的应用程序的用户“离线”访问他们的数据。因此,当我们运行同步脚本等时,我们可以立即访问他们的数据。 用户首次授予访问我们的应用程序的权限时(通过SSO,当用户单击我们的应用程序图标时),会要求用户授予访问我们需要的所有数据API的权限-联系人、电子邮件、日历等。一切正常,用户登录我们的应用程序。但当用户下次访问我们的应用程序时(同样通过SSO),它会被要求授予“离线访问权”。这很奇怪,因为第一次用户并没有被要求这样做。而且每次都要求用户“离线访问”看起来也不太好。为什么我们认为这样的行为奇怪是因为一旦用户已经授权访问。那么,为什么一次又一次地问这个问题呢

我们用于SSO的代码如下所示:

$clientId     = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com";
$clientSecret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
$callback     = "https://our_domain/callback";
$scopes       = array(
    "https://www.googleapis.com/auth/userinfo.email",
    "https://www.googleapis.com/auth/userinfo.profile",
    "https://www.googleapis.com/auth/drive.readonly.metadata",
    "https://www.googleapis.com/auth/calendar",
    "https://www.google.com/m8/feeds",
    "https://www.googleapis.com/auth/tasks",
    "https://www.googleapis.com/auth/admin.directory.user.readonly",
    "https://mail.google.com/"
);

// $params is a list of GET and POST parameters

if (empty($params['code']))
{
    $_SESSION['GOOGLE_SSO_STATE'] = md5(uniqid(rand(), true));

    $client = new Google_Client();

    $client->setClientId($clientId);
    $client->setRedirectUri($callback);
    $client->setAccessType('offline');
    $client->setApprovalPrompt('force');
    $client->setState($_SESSION['GOOGLE_SSO_STATE']);
    $client->setScopes($scopes);

    $url = $client->createAuthUrl();

    echo "<script> top.location.href='" . $url . "'</script>";
    exit;
}

if (!empty($params['code']) && !empty($params['state']) && $params['state'] == $_SESSION['GOOGLE_SSO_STATE'])
{
    unset($_SESSION['GOOGLE_SSO_STATE']);

    $client = new Google_Client();
    $client->setClientId($clientId);
    $client->setClientSecret($clientSecret);
    $client->setRedirectUri($callback);

    $credentials = $client->authenticate();

    // we need refresh token so we can exchange it for new access token when the current ones expires
    if (!isset($credentials_['refresh_token']))
    {
        echo "Wrong credentials received";
        exit;
    }

    $client = new Google_Client();
    $client->setUseObjects(true);
    $client->setAccessToken($credentials);

    $userInfoService = new Google_Oauth2Service($client);

    $userInfo = $userInfoService->userinfo->get();

    echo $userInfo->getId();
}
$clientId=“xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com”;
$clientSecret=“xxxxxxxxxxxxxxxxxxxxxxxxxxxxx”;
$callback=”https://our_domain/callback";
$scopes=数组(
"https://www.googleapis.com/auth/userinfo.email",
"https://www.googleapis.com/auth/userinfo.profile",
"https://www.googleapis.com/auth/drive.readonly.metadata",
"https://www.googleapis.com/auth/calendar",
"https://www.google.com/m8/feeds",
"https://www.googleapis.com/auth/tasks",
"https://www.googleapis.com/auth/admin.directory.user.readonly",
"https://mail.google.com/"
);
//$params是GET和POST参数的列表
if(空($params['code']))
{
$\会话['GOOGLE\u SSO\u STATE']=md5(uniqid(rand(),true));
$client=新的Google_客户端();
$client->setClientId($clientId);
$client->setRedirectUri($callback);
$client->setAccessType('offline');
$client->setApprovalPrompt('force');
$client->setState($_SESSION['GOOGLE\u SSO\u STATE']);
$client->setScopes($scopes);
$url=$client->createAuthUrl();
echo“top.location.href=”$url.“;
出口
}
如果(!empty($params['code'])和&!empty($params['state'])和&$params['state']==$\u会话['GOOGLE\u SSO\u state'])
{
取消设置($_会话['GOOGLE_SSO_状态]);
$client=新的Google_客户端();
$client->setClientId($clientId);
$client->setClientSecret($clientSecret);
$client->setRedirectUri($callback);
$credentials=$client->authenticate();
//我们需要刷新令牌,以便在当前令牌过期时将其替换为新的访问令牌
如果(!isset($credentials_['refresh_token']))
{
回显“收到错误的凭证”;
出口
}
$client=新的Google_客户端();
$client->setUseObjects(true);
$client->setAccessToken($credentials);
$userInfoService=newgoogle_Oauth2Service($client);
$userInfo=$userInfoService->userInfo->get();
echo$userInfo->getId();
}

有人能帮助我们理解这种行为吗?或者有人甚至知道如何让它在每次访问应用程序时不要求用户“离线访问”?

我们使用服务帐户,为安装域中的任何用户(为所选组织单元)提供离线访问。这可能是您的一个选择,具体取决于您正在尝试做什么


这是因为您的审批提示设置为“强制:


仅当您需要重新发布刷新令牌时才使用强制。有一个奇怪的副作用,会一次又一次地要求用户脱机访问。

非常感谢!
$client->setApprovalPrompt('auto');
工作正常,我只是将检查
刷新令牌“
移到了代码的另一部分(对于已经在DB中保存了凭据的用户跳过了它-这是我的一个大错误)。
 $client->setApprovalPrompt('force');