- 后端
- 电商
- 前端
【免费下载链接】CRMEB
🔥CRMEB开源商城免费开源多语言商城系统,Tp6框架商城,系统可商用;包含小程序商城、H5商城、公众号商城、PC商城、App,支持分销、拼团、砍价、秒杀、优惠券、积分、会员等级、小程序直播、页面DIY,前后端分离,方便二开,更有详细使用文档、接口文档、数据字典、二开文档/视频教程,欢迎大家提出宝贵意见和建议
本篇技术指南围绕 CRMEB 开源商城仓库中引入的官方 PHP 鉴权库google/auth(位于 crmeb/vendor/google/auth)展开,系统讲解如何在 PHP 项目中基于 OAuth 2.0 完成 Google API 的授权与认证,涵盖 Application Default Credentials(ADC)默认凭证、服务账号 JSON 密钥、Cloud Run / IAP 的 ID Token 场景,以及 JWT 校验等核心能力。读完本文,你将掌握从凭证准备、环境变量配置到 Guzzle 中间件挂载、API 调用的完整实战链路,并理解该库在源码层面的实现原理。
库概览:Google 官方 PHP 鉴权库及其在仓库中的定位
google/auth(Google Auth Library for PHP)是 Google 官方维护的 PHP 客户端鉴权库,用于在 PHP 应用中通过 OAuth 2.0 协议完成对 Google API 的授权(Authorization)与认证(Authentication),遵循 Apache 2.0 开源协议。其典型应用场景是:当应用调用 Google Cloud API(如 Drive、GCS 等)时,需要在请求中携带访问令牌,且调用身份与应用本身绑定、与最终用户无关。
在当前仓库中,该库作为 Composer 依赖被完整引入。从 crmeb/composer.lock 可以看到其锁定版本为v1.20.1,以 PSR-4 规范将Google\Auth\命名空间映射到 crmeb/vendor/google/auth/src。库源码的依赖约束记录在 crmeb/vendor/google/auth/composer.json 中:
- PHP:
^7.1||^8.0 firebase/php-jwt:~5.0(JWT 编解码底层实现)guzzlehttp/guzzle:^6.2.1|^7.0(HTTP 客户端)guzzlehttp/psr7、psr/http-message、psr/cache
值得一提的是,CRMEB 自身的登录态令牌体系也基于 JWT:项目封装的 crmeb/crmeb/utils/JwtAuth.php 直接使用Firebase\JWT\JWT的encode/decode方法配合应用app_key签发和校验 HS256 令牌。这意味着理解google/auth的令牌机制,与理解项目自身鉴权体系在原理上是贯通的。
通过 Composer 安装
官方推荐的安装方式是使用 Composer。先安装 Composer(已安装可跳过):
curl -sS https://getcomposer.org/installer | php随后执行以下命令安装最新稳定版:
composer.phar require google/auth安装完成后,库即被放置于vendor/google/auth目录,并通过 Composer 自动加载。在当前 CRMEB 仓库中,crmeb/vendor/google/auth/autoload.php 就是该库的自动加载入口。
Application Default Credentials:默认凭证体系
库的核心能力之一是对 Google 的Application Default Credentials(ADC)机制的 PHP 实现。ADC 提供了一种"无需在每处代码显式指定密钥文件"的简化获取凭证方式,适合应用以固定身份和固定授权级别调用 Google API 的场景,尤其适合构建在 Google Compute Engine 上的应用。
从源码看,ApplicationDefaultCredentials.php 的getCredentials()方法实现了完整的凭证查找优先级链:
- 读取
GOOGLE_APPLICATION_CREDENTIALS环境变量指向的 JSON 密钥文件(CredentialsLoader::fromEnv()); - 若环境变量未设置,则尝试读取"已知路径"下的默认凭证文件(
CredentialsLoader::fromWellKnownFile()); - 若在 App Engine 标准环境上运行,使用
AppIdentityCredentials; - 若在 GCE 上运行,则通过元数据服务器获取
GCECredentials; - 全部失败时抛出
DomainException。
该查找逻辑的具体实现位于 CredentialsLoader.php:fromEnv()读取环境变量、校验文件存在性并json_decode解析;fromWellKnownFile()则按操作系统约定查找默认路径——Windows 为%APPDATA%/gcloud/application_default_credentials.json,其他系统为$HOME/.config/gcloud/application_default_credentials.json。
下载服务账号凭证 JSON
使用 ADC 的第一步,是在 Google Developers Console 的APIs & Services > Credentials页面,从Add credentials下拉框中选择Service account,下载一份服务账号凭证 JSON 文件。
注意:该文件是这些凭证的唯一副本。它不应被提交进源代码仓库,而应被安全存储。
下载后将文件路径写入GOOGLE_APPLICATION_CREDENTIALS环境变量:
putenv('GOOGLE_APPLICATION_CREDENTIALS=/path/to/my/credentials.json');PHP 的putenv()只是设置环境变量的方式之一,也可以考虑使用.htaccess或 Apache 配置文件设置。
启用需要调用的 API
发起 API 调用前,必须在 Google Developers Console 的APIs & Auth > APIs页面启用目标 API。以下文示例为例,需要启用Drive API。
调用 API 的完整示例
完成凭证准备和环境变量设置后,即可通过 Guzzle 中间件将令牌注入请求。以下代码列出当前用户的 Drive 文件:
use Google\Auth\ApplicationDefaultCredentials; use GuzzleHttp\Client; use GuzzleHttp\HandlerStack; // 指定应用凭证路径 putenv('GOOGLE_APPLICATION_CREDENTIALS=/path/to/my/credentials.json'); // 定义本次 API 调用所需的 scopes $scopes = ['https://www.googleapis.com/auth/drive.readonly']; // 创建中间件 $middleware = ApplicationDefaultCredentials::getMiddleware($scopes); $stack = HandlerStack::create(); $stack->push($middleware); // 创建 HTTP 客户端 $client = new Client([ 'handler' => $stack, 'base_uri' => 'https://www.googleapis.com', 'auth' => 'google_auth' // 对所有请求授权 ]); // 发起请求 $response = $client->get('drive/v2/files'); // 展示结果 print_r((string) $response->getBody());源码层面的"google_auth"机制
'auth' => 'google_auth'是整条链路的触发开关。查看 AuthTokenMiddleware.php 的__invoke()实现可以看到:中间件会检查每个请求的auth选项,只有等于'google_auth'时才将Authorization: Bearer <token>头写入请求,否则直接透传。getMiddleware()内部会先调用getCredentials()完成凭证解析,再包装为AuthTokenMiddleware。此外,若凭证携带配额项目(quota project),中间件还会写入X-Goog-User-Project请求头用于账单归属。
Guzzle 5 兼容写法
若项目仍使用 Guzzle 5,需将上述"创建中间件"与"创建 HTTP 客户端"两步替换为以下写法:
// 创建 HTTP 客户端 $client = new Client([ 'base_url' => 'https://www.googleapis.com', 'auth' => 'google_auth' // 对所有请求授权 ]); // 创建 subscriber $subscriber = ApplicationDefaultCredentials::getSubscriber($scopes); $client->getEmitter()->attach($subscriber);使用 ID Token:Cloud Run 与 Cloud Identity-Aware Proxy(IAP)
当应用运行在 Cloud Run 之后,或通过 Cloud Identity-Aware Proxy(IAP)保护资源时,需要获取ID Token来访问应用。此时应使用ApplicationDefaultCredentials的静态方法getIdTokenMiddleware。
use Google\Auth\ApplicationDefaultCredentials; use GuzzleHttp\Client; use GuzzleHttp\HandlerStack; // 指定应用凭证路径 putenv('GOOGLE_APPLICATION_CREDENTIALS=/path/to/my/credentials.json'); // 指定 ID Token 的 audience: // 可以是与 IAP 应用关联的 Client ID // 也可以是 Cloud Run 应用的 URL // $targetAudience = 'IAP_CLIENT_ID.apps.googleusercontent.com'; // $targetAudience = 'https://service-1234-uc.a.run.app'; $targetAudience = 'YOUR_ID_TOKEN_AUDIENCE'; // 创建中间件 $middleware = ApplicationDefaultCredentials::getIdTokenMiddleware($targetAudience); $stack = HandlerStack::create(); $stack->push($middleware); // 创建 HTTP 客户端 $client = new Client([ 'handler' => $stack, 'auth' => 'google_auth', // Cloud Run、IAP 或自定义资源的 URL 'base_uri' => 'https://YOUR_PROTECTED_RESOURCE', ]); // 发起请求 $response = $client->get('/'); // 展示结果 print_r((string) $response->getBody());从实现看,getIdTokenMiddleware内部经由getIdTokenCredentials()(见 ApplicationDefaultCredentials.php)解析凭证,并校验 JSON 密钥中的type字段:必须是service_account,authorized_user(终端用户凭证)不支持签发 ID Token,否则抛出InvalidArgumentException。
权限前提(请以 Google Cloud 官方文档为准,此处仅为背景说明):
- 调用 Cloud Run 服务时,服务账号需要具备
Cloud Run InvokerIAM 权限; - 调用 IAP 时,需要将搭建受保护资源时使用的 Client ID 作为 target audience 传入。
使用 Proxy-Authorization 请求头场景
如果应用部署在 Google Cloud IAP 等代理之后,且应用的业务逻辑已经占用了Authorization请求头,可将 ID Token 改放入Proxy-Authorization: Bearer请求头。IAP 会校验该头中的 ID Token 并放行请求,同时将Authorization头原样传递给应用而不处理其内容。此时使用ApplicationDefaultCredentials::getProxyIdTokenMiddleware:
use Google\Auth\ApplicationDefaultCredentials; use GuzzleHttp\Client; use GuzzleHttp\HandlerStack; // 指定应用凭证路径 putenv('GOOGLE_APPLICATION_CREDENTIALS=/path/to/my/credentials.json'); // 指定 ID Token 的 audience(可以是与 IAP 应用关联的 Client ID) // $targetAudience = 'IAP_CLIENT_ID.apps.googleusercontent.com'; $targetAudience = 'YOUR_ID_TOKEN_AUDIENCE'; // 创建中间件 $middleware = ApplicationDefaultCredentials::getProxyIdTokenMiddleware($targetAudience); $stack = HandlerStack::create(); $stack->push($middleware); // 创建 HTTP 客户端 $client = new Client([ 'handler' => $stack, 'auth' => ['username', 'pass'], // 由应用自行处理的 auth 选项 'proxy_auth' => 'google_auth', ]); // 发起请求 $response = $client->get('/'); // 展示结果 print_r((string) $response->getBody());注意此处开关为'proxy_auth' => 'google_auth',中间件对应实现为Google\Auth\Middleware\ProxyAuthTokenMiddleware(在 src/Middleware 目录中),它与普通AuthTokenMiddleware的区别在于将 ID Token 写入Proxy-Authorization头而非Authorization头。
指定 JSON Key 调用:绕开环境变量
若不想依赖GOOGLE_APPLICATION_CREDENTIALS环境变量,而是显式指定某一 JSON 密钥,可以使用CredentialsLoader::makeCredentials手动加载凭证:
use Google\Auth\CredentialsLoader; use Google\Auth\Middleware\AuthTokenMiddleware; use GuzzleHttp\Client; use GuzzleHttp\HandlerStack; // 定义 Google Application Credentials 数组 $jsonKey = ['key' => 'value']; // 定义本次 API 调用所需的 scopes $scopes = ['https://www.googleapis.com/auth/drive.readonly']; // 加载凭证 $creds = CredentialsLoader::makeCredentials($scopes, $jsonKey); // 可选:令牌缓存 // $creds = new FetchAuthTokenCache($creds, $cacheConfig, $cache); // 创建中间件 $middleware = new AuthTokenMiddleware($creds); $stack = HandlerStack::create(); $stack->push($middleware); // 创建 HTTP 客户端 $client = new Client([ 'handler' => $stack, 'base_uri' => 'https://www.googleapis.com', 'auth' => 'google_auth' // 对所有请求授权 ]); // 发起请求 $response = $client->get('drive/v2/files'); // 展示结果 print_r((string) $response->getBody());从 CredentialsLoader.php 的实现可见,makeCredentials()依据 JSON 密钥中的type字段决定凭证类型:service_account生成ServiceAccountCredentials,authorized_user生成UserRefreshCredentials,其余值抛出InvalidArgumentException。凭证类均位于 crmeb/vendor/google/auth/src/Credentials 目录。
JWT 校验:验证 Google ID Token
常规校验
当使用 Google ID Token 认证用户时,使用Google\Auth\AccessToken类进行校验:
use Google\Auth\AccessToken; $auth = new AccessToken(); $auth->verify($idToken);IAP 场景下的校验
若应用运行在 Google Identity-Aware Proxy(IAP)之后,需要校验来自 IAP 服务器的 ID Token 时,应指定 IAP 专用的证书 URL。原因是 IAP 使用与 Google 身份服务不同的密钥对 ID Token 签名:
use Google\Auth\AccessToken; $auth = new AccessToken(); $auth->verify($idToken, [ 'certsLocation' => AccessToken::IAP_CERT_URL ]);查看 AccessToken.php 可确认两个关键常量:默认证书地址FEDERATED_SIGNON_CERT_URL = 'https://www.googleapis.com/oauth2/v3/certs',以及 IAP 专用证书地址IAP_CERT_URL = 'https://www.gstatic.com/iap/verify/public_key-jwk'和IAP_ISSUER。verify()方法支持audience、issuer、certsLocation、cacheKey、throwException等配置项,底层依赖firebase/php-jwt完成签名校验与过期检测,并提供基于 PSR-6 的证书缓存(默认使用MemoryCacheItemPool)。
结合 CRMEB 项目的实践视角
- 依赖现状:从 crmeb/composer.lock 可见
google/auth以v1.20.1版本随 Composer 依赖树安装(作为 Google 云相关 SDK 的传递依赖引入),完整源码与文档均保留在 crmeb/vendor/google/auth。 - JWT 原理贯通:本库通过
firebase/php-jwt完成令牌的签发与校验;CRMEB 项目自身的用户/管理员登录令牌同样基于Firebase\JWT\JWT实现(见 crmeb/crmeb/utils/JwtAuth.php),并设置了 60 秒leeway容差。理解本库有助于把握项目整体鉴权链路中 JWT 的编解码与密钥管理方式。 - 适用前提:若要真正调用 Google API,需要具备 Google Cloud 项目、服务账号凭证并启用对应 API;若仅运行 CRMEB 商城本身,则无需使用本库,项目自身的鉴权体系已由内置中间件与 JWT 工具类完成。
总结
google/auth提供了从 ADC 自动发现、服务账号密钥加载、Guzzle 中间件注入,到 ID Token 获取与 JWT 校验的一站式 PHP 鉴权能力。掌握"凭证查找优先级链 +google_auth触发开关 + 中间件注入"这条主线,即可在任意 PHP 项目中稳定、安全地接入 Google API;而理解其基于firebase/php-jwt的底层令牌机制,也能帮助你更好地理解像 CRMEB 这样依赖 JWT 构建鉴权体系的 PHP 应用的内部原理。
- 后端
- 电商
- 前端
【免费下载链接】CRMEB
🔥CRMEB开源商城免费开源多语言商城系统,Tp6框架商城,系统可商用;包含小程序商城、H5商城、公众号商城、PC商城、App,支持分销、拼团、砍价、秒杀、优惠券、积分、会员等级、小程序直播、页面DIY,前后端分离,方便二开,更有详细使用文档、接口文档、数据字典、二开文档/视频教程,欢迎大家提出宝贵意见和建议
相关推荐
google-api-python-client 的 OAuth 2.0 授权完整指南:从 Flow 到 Credentials 的实战全解
google api python client 的 OAuth 2.0 授权完整指南:从 Flow 到 Credentials 的实战全解 导读 本文以官方仓
后端google-api-php-client 服务账号 OAuth 2.0(Server to Server)授权实战指南
google api php client 服务账号 OAuth 2.0(Server to Server)授权实战指南 服务账号(Service Accoun
后端使用 google-api-nodejs-client 运行 Google Glass Mirror API 示例:OAuth 2.0 授权实战
使用 google api nodejs client 运行 Google Glass Mirror API 示例:OAuth 2.0 授权实战 导读 本文围绕
后端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考