OAuth 2.0
因为我们的服务器没有邮件服务器,所以我不得不在基于PHP的网页上实现这个功能,而是使用谷歌的邮件服务器。未经授权访问他们的服务可能会被谷歌禁止,因此我们需要一个具有未来性的解决方案。我相信将此解决方案移植到其他编程语言(如Java)应该不是什么大问题。
要求:
谷歌邮箱账户启用了云控制台,启用了https的Web域名,PHP 5.4或更高版本,并且安装了JSON扩展(自v5.2起捆绑在一起,但有时未安装 - 我们假设它已经安装)。还需要PHP Google API客户端库,可以通过以下方式获取:
- 服务器的命令行界面(CLI)和Composer依赖管理器。优点是您将自动接收更新。Google API库非常庞大,有方法可以排除不需要的部分。
或者
- 从其存储库手动复制库。优点是您只需要访问您的Web托管云服务,这在您无法使用Composer管理器的情况下非常有用。
1)Google控制台中的项目
首先,您需要在Google控制台中创建一个项目。 在与您的网页邮件发送应用程序相关联的帐户上执行此设置 - 是的,从谷歌的角度来看,这将是一个应用程序。 登录后:在项目选择的标题菜单中,选择并创建一个新项目(我的项目现在称为Gmail API)。我还将使用一个(不存在的)名为gmapi.xy的网页。
创建新项目后,进入库部分,找到Gmail API并启用它。
2)凭据
显然,您需要一些身份验证数据。启用API应该会将您重定向到Gmail API控制台界面 - 在左侧菜单中选择凭据:
创建新的OAuth客户端ID
- 但是您被告知要在OAuth同意屏幕上首先指定您的产品标题 - 选择创建新的OAuth客户端ID将在左侧菜单中显示同意屏幕选项卡。
2 a)创建产品(OAuth同意屏幕)
您需要填写名称、支持电子邮件、范围、授权域和OAuth限制
范围:
您需要指定授予任何将认证到Gmail API的人的所有权限:
授权域名:
填写您想要从中发送电子邮件的域名:
- 添加授权域 - 这些将被允许访问API(没有协议,仅顶级:
gmapi.xy
)
- 添加应用主页、隐私政策和服务条款链接 - 在我的情况下同上(但是完整地址:
https://gmapi.xy
或https://gmapi.xy/policy
等)
OAuth授权限制:
我对默认设置感到满意,因此没有更改(有关此主题的更多信息,请参见https://developers.google.com/analytics/devguides/config/mgmt/v3/limits-quotas)
保存更改:
保存表单。我们要求额外的范围 - 可能会看到警告:
此应用程序未经验证。
向用户呈现OAuth同意屏幕可能显示警告“此应用程序未经验证”,如果它正在请求提供对敏感用户数据的访问权限的范围。这些应用程序必须最终通过验证过程来删除该警告和其他限制。在开发阶段,您可以通过单击高级>转到{项目名称}(不安全)继续进行此警告。
一旦您的应用程序正在运行、公开且不处于开发阶段,请提交应用程序以进行验证(在保存
旁边的按钮)。您的新应用程序的验证可能需要多达几周。
2 b) 再次创建凭据
现在我们可以创建凭据 - 与以前一样,在左侧菜单中选择凭据。创建新的OAuth客户端ID。
- 选择“Web应用程序”作为类型
- 在“授权的 JavaScript 来源”中填写您的 URI。在我的情况下,是
https://gmapi.xy
和https://www.gmapi.xy
- 填写“授权重定向 URI”- Google 将要求用户授予权限,您必须指定允许 Google API 重定向回的 URI。在我的情况下,我正在使用
test.php
(具有https://www.gmapi.xy/test.php
URI),该文件被重定向到自身。因此,我将在那里添加https://www.gmapi.xy/test.php
和https://gmapi.xy/test.php
.
允许重定向 URL 存在许多问题。如果您的真实 URI 没有斜杠符号,则不能以/
符号结尾;如果使用非默认端口,则必须指定端口号等. 更多信息请参见此线程。
以下是您需要检查的清单:
- http 还是 https?
- & 还是 &?
- 末尾斜杠(/)还是打开状态?
- (CMD/CTRL)+F,在凭据页面中查找完全匹配项。如果没有找到,则搜索缺失的项目。
- 等待 Google 刷新。如果您经常进行更改,则可能每半个小时会发生,否则可能会停留在池中。对于我的情况,它几乎需要半个小时才能生效。
- 是否在更改 OAuth ID 中的值后重新导入了
credentials.json
文件?
注意:拥有多个允许的 URI 可能会损害脚本——在成功授权后,重定向回您的网页后仍然可能会出现此错误。
- 保存表单(您不必复制成功创建 OAuth ID 后提供给您的凭据 - 关闭弹窗)
- 下载
JSON
凭据文件- 在OAuth 2.0客户端ID部分,单击箭头图标
3 a) 使用Composer设置PHP
- 通过Composer安装Google API库:
composer require google/apiclient:^2.0
- 可选:运行
Google_Task_Composer::cleanup
任务,并在composer.json
中指定要保留的服务:
{
"require": {
"google/apiclient": "^2.7"
},
"scripts": {
"post-update-cmd": "Google_Task_Composer::cleanup"
},
"extra": {
"google/apiclient-services": [
"Drive",
"YouTube"
]
}
}
注意:目前这种方法似乎存在问题,尚未解决。因此,我没有尝试这个功能。我也找不到可用的服务名称列表,所以如果有人找到并添加了链接,那就好了。
3 b) 设置 PHP - 不使用 Composer
从发布版本中下载您需要的 PHP 版本的任何 .zip
(稳定版本),并将其放置在网站的某个位置(上传.zip
并在那里解压缩它)。
4 包含库、凭据和准备认证
也要上传 JSON
凭证文件。
安全提示:请将其放置在安全的地方:要么除了所有者外,删除任何人的 R/W 权限,要么使用 .htaccess
来保护此文件!
然后只需包含 autoload.php
(为其路径在服务器上查找库,应在 vendor
文件夹中),并提供用于身份验证的凭据。
require_once '/path/to/google-api-php-client/vendor/autoload.php';
$client = new Google_Client();
$client->setAuthConfig('/path/to/client_credentials.json');
此外,您需要请求范围特权并从服务中获取一个
token
。可用的范围列表在
这里。此外,请参见
此线程以获取更多关于权限范围的示例。
$client->setPrompt("consent");
$client->setScopes(array(
'https://www.googleapis.com/auth/gmail.send'
//add more if you want to have them, or add
// "https://mail.google.com/" to read, compose, send, delete mails
));
$client->setAccessType('offline');
$client->setIncludeGrantedScopes(true);
$tokenPath = 'where/you/want/to/store/token.json';
if (isset($_GET['code'])) {
$accessToken = $client->fetchAccessTokenWithAuthCode($_GET['code']);
if (!file_exists(dirname($tokenPath))) {
mkdir(dirname($tokenPath), 0700, true);
}
file_put_contents($tokenPath, json_encode($accessToken));
$client->setAccessToken($accessToken);
} else if (file_exists($tokenPath)) {
$accessToken = json_decode(file_get_contents($tokenPath), true);
$client->setAccessToken($accessToken);
}
if ($client->isAccessTokenExpired()) {
$refreshToken = $client->getRefreshToken();
if ($refreshToken) {
$client->fetchAccessTokenWithRefreshToken($refreshToken);
} else {
$redirect_uri = 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'];
$client->setRedirectUri($redirect_uri);
$auth_url = $client->createAuthUrl();
header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL));
}
}
起初,网页会将我们重定向至谷歌页面,在那里我们需要授权允许应用程序使用所需的电子邮件地址发送邮件。一旦获准,就会创建一个token文件并将其存储在一个文件中。当token过期时,可以使用
fetchAccessTokenWithRefreshToken()
自动创建新的token-详情请参阅
此处。
根据您的需求,可能需要限制身份验证的能力。我们使用API来获取对系统电子邮件的访问权限,而不是允许网站通过页面用户发送邮件,因此:
// Get the token - redirect to the same page
if ( user_not_administrator ) {
//TODO: redirect user to some error page and get yourself a notification
exit;
}
$redirect_uri = 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'];
5 发送电子邮件!
function createMessage($sender, $to, $subject, $messageText) {
$message = new Google_Service_Gmail_Message();
$rawMessageString = "From: <{$sender}>\r\n";
$rawMessageString .= "To: <{$to}>\r\n";
$rawMessageString .= 'Subject: =?utf-8?B?' . base64_encode($subject) . "?=\r\n";
$rawMessageString .= "MIME-Version: 1.0\r\n";
$rawMessageString .= "Content-Type: text/html; charset=utf-8\r\n";
$rawMessageString .= 'Content-Transfer-Encoding: quoted-printable' . "\r\n\r\n";
$rawMessageString .= "{$messageText}\r\n";
$rawMessage = strtr(base64_encode($rawMessageString), array('+' => '-', '/' => '_'));
$message->setRaw($rawMessage);
return $message;
}
function sendMessage($service, $userId, $message) {
try {
return $service->users_messages->send($userId, $message);
} catch (Exception $e) {
//todo error - use $e->getMessage();
}
return null;
}
sendMessage(new Google_Service_Gmail($client), 'me', createMessage(...));
Sources