0

0

使用PHP和Google Admin SDK列出用户所属群组:解决授权问题指南

碧海醫心

碧海醫心

发布时间:2025-12-04 11:25:17

|

822人浏览过

|

来源于php中文网

原创

使用php和google admin sdk列出用户所属群组:解决授权问题指南

本教程详细介绍了如何使用PHP和Google Admin SDK(Directory API)来获取Google Workspace用户所属的群组列表。文章聚焦于解决常见的“unauthorized_client”授权错误,并通过配置服务账号的域范围授权(Domain-Wide Delegation)、正确设置API Scope以及模拟域管理员身份(setSubject)来确保API调用的成功。通过清晰的步骤和代码示例,帮助开发者实现用户群组信息的程序化管理。

引言:使用PHP和Google Admin SDK管理用户群组

在Google Workspace环境中,管理员经常需要程序化地管理用户、群组、设备等资源。Google Admin SDK提供了一系列API,允许开发者通过代码实现这些管理功能。本教程将专注于如何利用PHP客户端库,结合Admin SDK的Directory API,来获取特定用户所属的群组列表。我们将特别关注在实现过程中可能遇到的授权问题,并提供一套完整的解决方案。

核心概念与前置条件

在开始编码之前,理解以下核心概念和完成必要的准备工作至关重要:

  1. Google Workspace Domain-Wide Delegation (DWD): DWD是Google Cloud平台的一项特性,允许服务账号(Service Account)代表Google Workspace域中的任何用户执行操作。这意味着,即使您的应用程序不是由特定用户直接授权的,它也可以在获得DWD授权后,以该用户的身份或管理员身份执行操作。这是访问Admin SDK的关键。

  2. 服务账号(Service Account): 服务账号是一种特殊的Google账号,用于服务器到服务器的交互,无需最终用户参与。它通过JSON密钥文件进行认证。

  3. Admin SDK Directory API: 这是Google Admin SDK的一部分,提供了管理用户、群组、组织单元等资源的接口。我们将使用其groups服务来查询群组信息。

  4. 所需权限(Scopes): API调用需要相应的授权范围(Scopes)。对于获取用户群组列表,至少需要以下Scope:

    • https://www.googleapis.com/auth/admin.directory.group.readonly:只读访问群组信息。
    • https://www.googleapis.com/auth/userinfo.email 和 https://www.googleapis.com/auth/userinfo.profile:用于获取当前认证用户的基本信息(如邮箱)。
  5. 准备工作

    立即学习PHP免费学习笔记(深入)”;

    • 启用Admin SDK API:在您的Google Cloud项目中,确保已启用Admin SDK API。
    • 创建服务账号与密钥
      1. 访问Google Cloud Console。
      2. 导航到“IAM & 管理” youjiankuohaophpcn “服务账号”。
      3. 创建一个新的服务账号。
      4. 为该服务账号生成一个新的JSON密钥,并下载到您的项目目录中。
    • 配置服务账号的DWD
      1. 在Google Cloud Console的服务账号详情页,找到服务账号的唯一客户端ID。
      2. 登录Google Workspace管理员控制台(admin.google.com)。
      3. 导航到“安全性” > “API 控件” > “域范围委派”。
      4. 添加新的API客户端,输入服务账号的客户端ID,并授权上述所需的API Scope(特别是 https://www.googleapis.com/auth/admin.directory.group.readonly)。
    • Composer安装Google API客户端库: 在您的PHP项目中,通过Composer安装Google API客户端库:
      composer require google/apiclient:^2.0

PHP代码实现:获取用户群组列表

以下是实现获取用户群组列表的PHP代码示例,它结合了用户OAuth认证获取用户邮箱和通过服务账号进行Admin SDK调用的策略。

一点PPT
一点PPT

一句话生成专业PPT,AI自动排版配图

下载

步骤一:用户认证与信息获取

首先,我们需要通过标准的OAuth 2.0流程让用户登录,并获取其邮箱地址。这个邮箱将用于后续查询该用户所属的群组。

<?php

require 'vendor/autoload.php'; // 根据您的项目路径调整

// 创建新的Google客户端实例
$client = new Google_Client();

// 配置OAuth客户端凭据
// 这些信息通常在Google Cloud Console的OAuth同意屏幕或凭据页面获取
$client->setClientId('YOUR_CLIENT_ID.apps.googleusercontent.com'); // 替换为您的客户端ID
$client->setClientSecret('YOUR_CLIENT_SECRET'); // 替换为您的客户端密钥
$client->setRedirectUri('YOUR_REDIRECT_URL'); // 替换为您的重定向URL
$client->setApplicationName("Your Application Name"); // 替换为您的应用名称

// 添加获取用户邮箱和个人资料信息的Scope
$client->addScope("https://www.googleapis.com/auth/userinfo.email");
$client->addScope("https://www.googleapis.com/auth/userinfo.profile");
// 仅为Admin SDK操作添加的Scope,这里先不添加,后面服务账号认证时再添加
// $client->addScope("https://www.googleapis.com/auth/admin.directory.group.readonly");

$userEmail = '';

// 处理OAuth回调
if (isset($_GET['code'])) {
    $token = $client->fetchAccessTokenWithAuthCode($_GET['code']);

    if (!isset($token["error"])) {
        $client->setAccessToken($token['access_token']);

        // 获取用户个人资料信息
        $google_oauth = new Google_Service_Oauth2($client);
        $google_account_info = $google_oauth->userinfo->get();

        $userEmail = $google_account_info->email;
        echo "当前登录用户邮箱: " . $userEmail . "<br>";

    } else {
        echo "OAuth认证失败: " . $token["error_description"] . "<br>";
    }
} else {
    // 如果没有认证码,则重定向到Google认证页面
    $authUrl = $client->createAuthUrl();
    echo "<a href='" . $authUrl . "'>点击此处登录Google</a>";
    exit;
}

// ... 接下来是服务账号授权和群组查询
?>

步骤二:服务账号授权与群组查询

在获取到用户邮箱后,我们将切换到服务账号的认证模式,并利用域范围授权来查询该用户所属的群组。

<?php
// ... (接上一步骤代码,确保 $userEmail 已被获取)

if (!empty($userEmail)) {
    // 重新配置客户端,使用服务账号进行认证
    // 注意:这里我们重用了 $client 实例,但实际上可以创建新的实例以避免混淆
    // 为了教程的简洁性,我们在此重用并覆盖了认证配置。
    // 在生产环境中,可能需要更清晰的客户端管理。

    // 设置服务账号的JSON密钥文件路径
    $client->setAuthConfig('path/to/your/service-account-key.json'); // 替换为您的JSON密钥文件路径

    // 设置要模拟的管理员邮箱。此邮箱必须是Google Workspace域内的管理员账号,
    // 并且具有读取群组的权限。这是DWD的关键一步。
    $client->setSubject('admin-user@yourdomain.com'); // 替换为您的域管理员邮箱

    // 添加Admin SDK Directory API的只读Scope
    // 注意:这个Scope必须在Google Workspace管理员控制台的DWD中授权给服务账号
    $client->addScope("https://www.googleapis.com/auth/admin.directory.group.readonly");

    try {
        // 实例化Google Directory服务
        $service = new Google_Service_Directory($client);

        // 配置查询参数:指定域和要查询的用户邮箱
        $optParams = array(
            'domain' => 'yourdomain.com', // 替换为您的Google Workspace域名
            'userKey' => $userEmail      // 查询此用户所属的群组
        );

        // 调用listGroups方法获取群组列表
        $googleGroups = $service->groups->listGroups($optParams);
        $groups = $googleGroups->getGroups();

        if (!empty($groups)) {
            echo "<h2>用户 " . $userEmail . " 所属群组列表:</h2>";
            echo "<ul>";
            foreach ($groups as $group) {
                echo "<li>" . $group->getName() . " (" . $group->getEmail() . ")</li>";
            }
            echo "</ul>";
        } else {
            echo "用户 " . $userEmail . " 未找到所属群组或无权限访问。<br>";
        }

    } catch (Google_Service_Exception $e) {
        echo "获取群组时发生错误: " . $e->getMessage() . "<br>";
        // 详细错误信息可能在 $e->getErrors() 中
    } catch (Exception $e) {
        echo "未知错误: " . $e->getMessage() . "<br>";
    }
} else {
    echo "无法获取用户邮箱,请先完成OAuth认证。<br>";
}
?>

完整示例代码

将上述两个步骤的代码整合,形成一个完整的PHP脚本:

<?php

require 'vendor/autoload.php';

// --- 配置部分 ---
$clientId = 'YOUR_CLIENT_ID.apps.googleusercontent.com'; // 替换为您的OAuth客户端ID
$clientSecret = 'YOUR_CLIENT_SECRET'; // 替换为您的OAuth客户端密钥
$redirectUri = 'YOUR_REDIRECT_URL'; // 替换为您的重定向URL (必须与Google Cloud Console中配置的一致)
$appName = "My Google Group Lister"; // 替换为您的应用名称
$serviceAccountKeyPath = 'path/to/your/service-account-key.json'; // 替换为您的服务账号JSON密钥文件路径
$adminImpersonationEmail = 'admin-user@yourdomain.com'; // 替换为具有群组读取权限的域管理员邮箱
$googleWorkspaceDomain = 'yourdomain.com'; // 替换为您的Google Workspace域名
// --- 配置部分结束 ---

// 创建Google客户端实例
$client = new Google_Client();
$client->setApplicationName($appName);

$userEmail = '';

// --- 步骤一:用户认证与信息获取 ---
// 用于获取当前登录用户的邮箱,以便后续查询其群组
$client->setClientId($clientId);
$client->setClientSecret($clientSecret);
$client->setRedirectUri($redirectUri);
$client->addScope("https://www.googleapis.com/auth/userinfo.email");
$client->addScope("https://www.googleapis.com/auth/userinfo.profile");

if (isset($_GET['code'])) {
    $token = $client->fetchAccessTokenWithAuthCode($_GET['code']);

    if (!isset($token["error"])) {
        $client->setAccessToken($token['access_access_token']);

        $google_oauth = new Google_Service_Oauth2($client);
        $google_account_info = $google_oauth->userinfo->get();
        $userEmail = $google_account_info->email;

        echo "当前登录用户邮箱: " . htmlspecialchars($userEmail) . "<br>";

        // --- 步骤二:服务账号授权与群组查询 ---
        // 重新配置客户端,使用服务账号进行认证,以执行Admin SDK操作
        $client->setAuthConfig($serviceAccountKeyPath);
        $client->setSubject($adminImpersonationEmail); // 模拟域管理员
        // 确保服务账号已通过DWD授权此Scope
        $client->addScope("https://www.googleapis.com/auth/admin.directory.group.readonly");

        try {
            $service = new Google_Service_Directory($client);

            $optParams = array(
                'domain' => $googleWorkspaceDomain,
                'userKey' => $userEmail
            );

            $googleGroups = $service->groups->listGroups($optParams);
            $groups = $googleGroups->getGroups();

            if (!empty($groups)) {
                echo "<h2>用户 " . htmlspecialchars($userEmail) . " 所属群组列表:</h2>";
                echo "<ul>";
                foreach ($groups as $group) {
                    echo "<li>" . htmlspecialchars($group->getName()) . " (" . htmlspecialchars($group->getEmail()) . ")</li>";
                }
                echo "</ul>";
            } else {
                echo "用户 " . htmlspecialchars($userEmail) . " 未找到所属群组或无权限访问。<br>";
            }

        } catch (Google_Service_Exception $e) {
            echo "获取群组时发生API错误: " . htmlspecialchars($e->getMessage()) . "<br>";
            // 更多错误信息: print_r($e->getErrors());
        } catch (Exception $e) {
            echo "发生未知错误: " . htmlspecialchars($e->getMessage()) . "<br>";
        }

    } else {
        echo "OAuth认证失败: " . htmlspecialchars($token["error_description"]) . "<br>";
    }
} else {
    // 如果没有认证码,则生成认证URL并重定向
    $authUrl = $client->createAuthUrl();
    echo "<p><a href='" . htmlspecialchars($authUrl) . "'>点击此处登录Google并授权</a></p>";
}
?>

注意事项与常见问题解决

  1. unauthorized_client 错误解析: 这个错误通常表示您的客户端没有足够的权限执行请求的操作。针对本教程的场景,最常见的原因是:

    • 服务账号未配置DWD:确保服务账号的客户端ID已在Google Workspace管理员控制台的“域范围委派”中添加,并授权了所有必要的Scope(特别是 https://www.googleapis.com/auth/admin.directory.group.readonly)。
    • setSubject 邮箱不正确或无权限:setSubject 中指定的邮箱必须是您的Google Workspace域内的管理员账号,并且该管理员账号本身拥有读取群组的权限。如果模拟的用户没有权限,即使服务账号有DWD,操作也会失败。
    • JSON密钥文件路径错误或文件损坏:确保 setAuthConfig() 指向正确的服务账号JSON密钥文件。
    • Scope缺失或不匹配:确保 addScope() 中添加的Scope与DWD中授权给服务账号的Scope完全一致。
  2. setSubject 的作用: $client->setSubject('admin-user@yourdomain.com'); 这一行是DWD的核心。它告诉Google API客户端,服务账号将代表 admin-user@yourdomain.com 这个用户执行后续操作。因此,admin-user@yourdomain.com 必须是一个实际存在的、具有相应权限的域内管理员账号。

  3. Scope的正确使用

    • 用于用户OAuth认证的Scope(如 userinfo.email)与用于服务账号DWD的Admin SDK Scope(如 admin.directory.group.readonly)是不同的。确保在相应阶段添加正确的Scope。
    • 请记住,即使代码中添加了Scope,最终的权限仍然受限于Google Workspace管理员控制台中为服务账号配置的DWD。
  4. JSON密钥文件的安全性: 服务账号的JSON密钥文件包含敏感凭据,应像对待密码一样妥善保管。不要将其上传到公共代码仓库,并确保服务器上的文件权限设置正确,仅限应用程序访问。

  5. API速率限制: Google API对请求有速率限制。在进行大量查询时,请注意处理API响应中的错误(如429 Too Many Requests),并实现适当的重试机制和退避策略。

总结

通过本教程,我们学习了如何利用PHP和Google Admin SDK(Directory API)来获取Google Workspace用户的群组列表。成功的关键在于正确配置服务账号的域范围授权,确保所需的API Scope已在Google Workspace管理员控制台授权,并在代码中通过 setAuthConfig() 加载服务账号密钥并通过 setSubject() 模拟具有相应权限的域管理员。遵循这些步骤,可以有效解决常见的授权问题,实现对Google Workspace资源的程序化管理。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
composer是什么插件
composer是什么插件

Composer是一个PHP的依赖管理工具,它可以帮助开发者在PHP项目中管理和安装依赖的库文件。Composer通过一个中央化的存储库来管理所有的依赖库文件,这个存储库包含了各种可用的依赖库的信息和版本信息。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

162

2023.12.25

json数据格式
json数据格式

JSON是一种轻量级的数据交换格式。本专题为大家带来json数据格式相关文章,帮助大家解决问题。

457

2023.08.07

json是什么
json是什么

JSON是一种轻量级的数据交换格式,具有简洁、易读、跨平台和语言的特点,JSON数据是通过键值对的方式进行组织,其中键是字符串,值可以是字符串、数值、布尔值、数组、对象或者null,在Web开发、数据交换和配置文件等方面得到广泛应用。本专题为大家提供json相关的文章、下载、课程内容,供大家免费下载体验。

549

2023.08.23

jquery怎么操作json
jquery怎么操作json

操作的方法有:1、“$.parseJSON(jsonString)”2、“$.getJSON(url, data, success)”;3、“$.each(obj, callback)”;4、“$.ajax()”。更多jquery怎么操作json的详细内容,可以访问本专题下面的文章。

337

2023.10.13

go语言处理json数据方法
go语言处理json数据方法

本专题整合了go语言中处理json数据方法,阅读专题下面的文章了解更多详细内容。

82

2025.09.10

硬盘接口类型介绍
硬盘接口类型介绍

硬盘接口类型有IDE、SATA、SCSI、Fibre Channel、USB、eSATA、mSATA、PCIe等等。详细介绍:1、IDE接口是一种并行接口,主要用于连接硬盘和光驱等设备,它主要有两种类型:ATA和ATAPI,IDE接口已经逐渐被SATA接口;2、SATA接口是一种串行接口,相较于IDE接口,它具有更高的传输速度、更低的功耗和更小的体积;3、SCSI接口等等。

1948

2023.10.19

PHP接口编写教程
PHP接口编写教程

本专题整合了PHP接口编写教程,阅读专题下面的文章了解更多详细内容。

658

2025.10.17

php8.4实现接口限流的教程
php8.4实现接口限流的教程

PHP8.4本身不内置限流功能,需借助Redis(令牌桶)或Swoole(漏桶)实现;文件锁因I/O瓶颈、无跨机共享、秒级精度等缺陷不适用高并发场景。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2401

2025.12.29

TypeScript类型系统进阶与大型前端项目实践
TypeScript类型系统进阶与大型前端项目实践

本专题围绕 TypeScript 在大型前端项目中的应用展开,深入讲解类型系统设计与工程化开发方法。内容包括泛型与高级类型、类型推断机制、声明文件编写、模块化结构设计以及代码规范管理。通过真实项目案例分析,帮助开发者构建类型安全、结构清晰、易维护的前端工程体系,提高团队协作效率与代码质量。

26

2026.03.13

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PHP课程
PHP课程

共137课时 | 13.5万人学习

JavaScript ES5基础线上课程教学
JavaScript ES5基础线上课程教学

共6课时 | 11.3万人学习

PHP新手语法线上课程教学
PHP新手语法线上课程教学

共13课时 | 1.0万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号