PHP环境下如何合理使用Microsoft Graph API的Access Token
Microsoft Graph API(客户端凭据流)Access Token的使用优化
问题核心
你当前每次页面加载都调用getAccessToken()请求新的Access Token,功能可行但效率低下,完全没必要这么做,下面是具体的优化方案和相关细节:
1. Access Token的有效期
客户端凭据流(client_credentials)获取的Microsoft Graph Access Token,默认有效期是3600秒(1小时),这个值会在token请求的响应体expires_in字段里返回,你可以直接读取该值计算过期时间。
2. 当前实现的问题
每次页面加载都请求新token,会:
- 增加Azure AD的请求次数,可能触发限流
- 浪费服务器和网络资源,完全没必要重复获取未过期的token
3. 最佳实践:缓存Access Token
因为你用的是客户端凭据流,这个token是应用级别的(非用户专属),所以应该在服务器端全局缓存,而非存在用户Session里(Session是用户会话级,不同用户共享同一个应用token即可)。
优化后的代码示例(带文件缓存)
// 带缓存的Access Token获取函数 function getAccessToken() { $cacheFile = __DIR__ . '/ms_graph_token_cache.json'; $clientId = ""; $clientSecret = ""; $tenant_id = ""; $grantType = "client_credentials"; $resource = "https://graph.microsoft.com"; $tokenEndpoint = "https://login.microsoftonline.com/$tenant_id/oauth2/token"; // 检查缓存是否存在且未过期(提前5分钟刷新,避免刚好过期的情况) if (file_exists($cacheFile)) { $cacheData = json_decode(file_get_contents($cacheFile), true); if (time() < $cacheData['expires_at'] - 300) { return $cacheData['access_token']; } } // 缓存失效,请求新token $requestBody = "client_id=$clientId&client_secret=$clientSecret&grant_type=$grantType&resource=$resource"; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $tokenEndpoint); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); // 建议开启SSL验证,关闭有安全风险 curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, $requestBody); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); $response = curl_exec($ch); curl_close($ch); $responseJson = json_decode($response, true); if (!isset($responseJson['access_token'])) { // 处理token请求失败的情况,比如抛出异常或返回错误 throw new Exception("Failed to get access token: " . json_encode($responseJson)); } // 计算过期时间并缓存 $cacheData = [ 'access_token' => $responseJson['access_token'], 'expires_at' => time() + $responseJson['expires_in'] ]; file_put_contents($cacheFile, json_encode($cacheData)); return $responseJson['access_token']; }
缓存方案选择
- 单服务器部署:可以用文件缓存、APC/uopz等内存缓存
- 多服务器部署:建议用Redis、Memcached等分布式缓存,确保所有服务器共享同一个token缓存
4. 关键注意事项
- 不要把token暴露给前端:客户端凭据流的token拥有应用级权限,权限很高,泄露后会导致租户数据风险
- 开启SSL验证:你原来的代码关闭了
CURLOPT_SSL_VERIFYPEER,这会有中间人攻击风险,建议开启(默认是true,可直接去掉关闭验证的代码) - 错误处理:加入token请求失败的处理逻辑,避免因为token获取失败导致整个功能崩溃
- 定期轮换Client Secret:在Azure AD里定期更新应用的Client Secret,避免泄露风险
内容的提问来源于stack exchange,提问作者PaulieShore
相关产品推荐
相关产品推荐

