如何通过JS/PHP重置Google OAuth API的id_token
Google 登录安全实现修正方案
你观察到的id_token永久不变是前端取值逻辑错误导致的,Google签发的id_token默认有效期仅1小时,本身不存在永久有效的设计问题。你无权通过PHP/JS重置Google签发的id_token,只需要修正前后端取值、校验逻辑即可实现无额外依赖的安全登录流程。
前端JS修正(基于原有gapi库,无需新增依赖)
你原有代码直接读取gapi缓存的首次登录返回的authResponse对象,不会自动拉取最新的有效token,需要主动调用reloadAuthResponse方法刷新获取最新id_token,修正后代码:
function gmailLogin(userInfo) { const authInstance = gapi.auth2.getAuthInstance(); const currentUser = authInstance.currentUser.get(); // 主动刷新获取最新有效鉴权响应,避免拿到过期/旧token currentUser.reloadAuthResponse().then(authResponse => { const token_id = authResponse.id_token; jQuery.ajax({ url: "functions/login_check.php", type: "post", data: {token_id: token_id}, success: function(data) { $('#console').html(data); } }); }).catch(err => { // 刷新失败则引导用户重新登录 authInstance.signIn(); }); }
纯PHP无依赖安全校验逻辑
你现有后端代码仅校验email_verified字段存在严重安全漏洞,攻击者可以伪造其他应用签发的有效token绕过校验,必须补全以下校验规则:
- 校验请求Google tokeninfo接口返回的响应无错误
- 校验签发方
iss字段值为合法的Google域名:accounts.google.com或https://accounts.google.com - 校验受众
aud字段严格等于你在Google Cloud控制台申请的本网站客户端ID,杜绝其他应用的token冒用 - 校验过期时间
exp字段大于当前服务器时间戳,拒绝过期token - 校验
email_verified字段为布尔值true,仅对完成邮箱验证的账号放行
补全后的纯PHP实现代码(无任何外部依赖,不需要引入Google官方SDK):
<?php // 替换为你自己在Google Cloud控制台申请的Web端客户端ID const GOOGLE_CLIENT_ID = '你的谷歌客户端ID.apps.googleusercontent.com'; if (!isset($_POST['token_id']) || empty($_POST['token_id'])) { exit('无效请求'); } $token_id = $_POST['token_id']; // 调用Google公开接口校验token $verifyResponse = file_get_contents('https://oauth2.googleapis.com/tokeninfo?id_token='.urlencode($token_id)); if (!$verifyResponse) { exit('token校验请求失败'); } $response = json_decode($verifyResponse); if (!$response || isset($response->error)) { exit('无效token'); } // 全字段安全校验 $isValidIss = in_array($response->iss, ['accounts.google.com', 'https://accounts.google.com']); $isValidAud = $response->aud === GOOGLE_CLIENT_ID; $isNotExpired = $response->exp > time(); $isEmailVerified = isset($response->email_verified) && $response->email_verified === 'true'; if (!$isValidIss || !$isValidAud || !$isNotExpired || !$isEmailVerified) { exit('身份校验失败'); } // 校验通过,执行自有网站登录逻辑:根据$response->sub(用户在Google的唯一标识)对应用户表账号,写入session即可 // 注意:优先使用$response->sub作为用户唯一标识,不要用邮箱,因为邮箱可能被用户修改 $userGoogleId = $response->sub; $userEmail = $response->email; $userName = $response->name;
补充安全提示:登录逻辑不要用邮箱作为Google账号的唯一关联标识,一定要用返回的
sub字段,该字段是Google为每个用户生成的全局唯一不变标识,邮箱存在用户修改、跨账号复用的风险。
内容的提问来源于stack exchange,提问作者Web Dev
相关产品推荐
相关产品推荐

