如何将PHPMailer get_oauth_token.php的输出加载到指定div中?
解决OAuth2授权不跳转整页的方案
1. 重构后端授权逻辑,取消直接跳转
把原get_oauth_token.php的流程拆成两个独立接口,避免用header()触发整页跳转:
接口1:生成授权链接
在MVC的Admin控制器里新增方法,负责生成谷歌授权URL和state,以JSON格式返回给前端:
public function getOAuthUrl() { session_start(); $client = new Google_Client(); $client->setClientId('你的谷歌ClientID'); $client->setClientSecret('你的谷歌ClientSecret'); $client->setRedirectUri('http://localhost/Admin/oauthCallback'); // 配置回调地址 $client->addScope('https://mail.google.com/'); $client->setAccessType('offline'); $client->setPrompt('select_account consent'); $authUrl = $client->createAuthUrl(); $_SESSION['oauth2state'] = $client->getState(); header('Content-Type: application/json'); echo json_encode([ 'authUrl' => $authUrl, 'state' => $_SESSION['oauth2state'] ]); exit; }
接口2:处理授权回调
同样在Admin控制器里新增回调方法,接收谷歌返回的code并换取token,返回结果:
public function oauthCallback() { session_start(); if (!isset($_GET['state']) || $_GET['state'] !== $_SESSION['oauth2state']) { unset($_SESSION['oauth2state']); header('Content-Type: application/json'); echo json_encode(['error' => '无效的state参数']); exit; } $client = new Google_Client(); $client->setClientId('你的谷歌ClientID'); $client->setClientSecret('你的谷歌ClientSecret'); $client->setRedirectUri('http://localhost/Admin/oauthCallback'); $client->addScope('https://mail.google.com/'); $token = $client->fetchAccessTokenWithAuthCode($_GET['code']); $client->setAccessToken($token); // 把token存入session或数据库,供后续发信使用 $_SESSION['gmail_oauth_token'] = $token; header('Content-Type: application/json'); echo json_encode([ 'success' => true, 'msg' => '授权成功' ]); exit; }
2. 前端用弹窗处理授权流程
谷歌OAuth2禁止在iframe中加载授权页,所以用浏览器弹窗打开授权链接,完成后回调更新指定div:
<!-- 页面元素 --> <button id="bindGmail">绑定谷歌邮箱</button> <div id="oauthResult"></div> <script> document.getElementById('bindGmail').addEventListener('click', function() { // 异步请求授权链接 fetch('/Admin/getOAuthUrl') .then(res => res.json()) .then(data => { // 计算弹窗居中位置 const w = 600; const h = 600; const left = (window.innerWidth - w) / 2; const top = (window.innerHeight - h) / 2; // 打开授权弹窗 const authWin = window.open( data.authUrl, 'GoogleOAuth', `width=${w},height=${h},left=${left},top=${top},scrollbars=yes` ); // 定时检查弹窗状态 const checkTimer = setInterval(() => { if (authWin.closed) { clearInterval(checkTimer); // 弹窗关闭后查询授权结果 fetch('/Admin/checkOAuthStatus') // 新增接口:检查session中是否存在token .then(res => res.json()) .then(result => { if (result.success) { document.getElementById('oauthResult').innerHTML = '<p>谷歌邮箱绑定成功!</p>'; } else { document.getElementById('oauthResult').innerHTML = '<p>绑定失败,请重试</p>'; } }); } }, 1000); }) .catch(err => { document.getElementById('oauthResult').innerHTML = `<p>获取授权链接失败:${err.message}</p>`; }); }); </script>
3. 关键注意事项
- 确保谷歌开发者控制台里的授权回调地址和后端配置完全一致,本地开发可填
http://localhost/Admin/oauthCallback。 - MVC架构中要确保Session正常启用,避免state验证失败。
- 建议将获取到的token加密后存入数据库,而非仅存在Session中,方便后续调用PHPMailer发信。
内容的提问来源于stack exchange,提问作者Teo76
相关产品推荐
相关产品推荐

