PHP中使用Access Token访问Microsoft Graph API的SDK问题咨询
问题1:InMemoryAccessTokenCache初始化错误解决
错误原因
你传入的AccessToken参数中,expires使用了相对过期时间(3600秒),但AccessToken类要求该值为绝对时间戳(从Unix纪元开始的秒数)。另外,用包含一次性授权码的AuthorizationCodeContext初始化缓存,也会导致缓存键生成失败。
修正步骤
- 正确构造
AccessToken实例,将expires改为绝对时间戳:$accessToken = new AccessToken([ 'access_token' => $token->access_token, 'refresh_token' => $token->refresh_token, 'expires' => time() + 3600 // 当前时间加上有效期,生成绝对时间戳 ]); - 使用
RefreshTokenContext替代AuthorizationCodeContext初始化缓存,避免授权码干扰:$tokenRequestContext = new RefreshTokenContext( "tenantId", "clientId", "clientSecret", $token->refresh_token // 直接传入已获取的refresh_token ); - 重新初始化缓存与客户端:
$cache = new InMemoryAccessTokenCache($tokenRequestContext, $accessToken); $client = GraphServiceClient::createWithAuthenticationProvider( GraphPhpLeagueAuthenticationProvider::createWithAccessTokenProvider( GraphPhpLeagueAccessTokenProvider::createWithCache( $cache, $tokenRequestContext, ["offline_access", "user.read", "mail.read", "mail.send", "mail.readbasic", "mail.readwrite", "imap.accessasuser.all", "smtp.send"] ) ) );
问题2:解决仅能发起一次请求、后续"Invalid grant"错误
错误原因
授权码(authCode)是一次性使用凭证,用它获取令牌后授权码立即失效,重复使用会触发"Invalid grant"错误。
实现多次请求的方案
- 持久化存储refresh_token:首次用授权码获取到
access_token和refresh_token后,将refresh_token保存到数据库、文件等持久化介质,不要每次请求都用授权码初始化客户端。 - 用RefreshTokenContext初始化客户端:后续请求直接读取保存的
refresh_token创建RefreshTokenContext,SDK会自动在access_token过期时,用refresh_token刷新获取新令牌,无需手动处理。 - 使用持久化缓存(可选):如果需要跨会话保持令牌,不要用
InMemoryAccessTokenCache,改用基于数据库或文件的自定义缓存类,确保令牌在多次请求间保留并自动刷新。
完整示例代码
首次获取并保存refresh_token(仅执行一次)
// 首次用授权码获取令牌 $tokenRequestContext = new AuthorizationCodeContext( "tenantId", "clientId", "clientSecret", "authCode", "redirectUrl" ); $tokenProvider = new GraphPhpLeagueAccessTokenProvider($tokenRequestContext, ["offline_access", "user.read", "mail.read"]); $accessToken = $tokenProvider->getAccessToken(); // 自定义函数:将refresh_token保存到持久化存储 saveRefreshToken($accessToken->getRefreshToken());
后续多次请求使用refresh_token
// 自定义函数:从持久化存储读取refresh_token $savedRefreshToken = getSavedRefreshToken(); // 用refresh_token创建上下文 $tokenRequestContext = new RefreshTokenContext( "tenantId", "clientId", "clientSecret", $savedRefreshToken ); // 初始化缓存与令牌提供者 $cache = new InMemoryAccessTokenCache($tokenRequestContext); $tokenProvider = GraphPhpLeagueAccessTokenProvider::createWithCache( $cache, $tokenRequestContext, ["offline_access", "user.read", "mail.read", "mail.send", "mail.readbasic", "mail.readwrite", "imap.accessasuser.all", "smtp.send"] ); // 创建客户端并发起多次请求 $client = GraphServiceClient::createWithAuthenticationProvider( GraphPhpLeagueAuthenticationProvider::createWithAccessTokenProvider($tokenProvider) ); // 第一次请求 $me = $client->me()->get()->wait(); // 第二次请求(自动处理令牌刷新) $messages = $client->me()->messages()->get()->wait();
内容的提问来源于stack exchange,提问作者Jongkwan Park




