我正在尝试使用Microsoft的Graph API在PHP中创建一个(有点)无缝的应用程序。该应用程序将通过命令行运行,但是对于初始授权,它指示用户在其浏览器中打开授权URL。重定向URI是相同的脚本,因此当Microsoft使用代码重定向回时,我将其捕获并将其保存到服务器上的文件中。
然后,用户返回命令行并再次运行该应用程序。 此时,应用程序将检索用户的所有电子邮件数据(标题和消息数据)以进行处理。
一切顺利进行,直到我的令牌到期为止。我最终不得不删除令牌文件并重新开始该过程。调试时不方便,在生产中绝对是不希望的。理想情况下,我想简单地在后台刷新令牌,并使处理继续进行而不会中断。
我的脚本:
$rootPath = dirname(__DIR__);
require $rootPath.'/common.php';
require $rootPath.'/lib/microsoft.php';
$ms = new Azure();
// check if there is an existing token file, and use that token if there is.
$tokenPath = $rootPath.'/assets/files/tokens/ms.json';
if(file_exists($tokenPath)){
$string = file_get_contents($tokenPath);
$token = json_decode($string, true);
process($token);
}else{
// there is no existing token file, so we must obtain, or be obtaining a new one.
if(isset($_GET['code'])){
// obtaining a new token from Microsoft
$accessToken = $ms->obtainToken($_GET['code']);
$token = $accessToken->jsonSerialize();
// save token to file
saveFile($tokenPath, json_encode($token));
process($token);
}else{
// initial run. we must first login and redirect back to obtain an auth code
$authUrl = $ms->getClient()->getAuthorizationUrl();
printf("Open the following link in your browser:\n%s\n", $authUrl);
}
}
function process($token){
global $ms;
// obtain a graph instance with the token we have
$graph = $ms->getGraph($token);
$messages = $ms->getMessages();
foreach($messages as $msg){
$headers = $msg['headers'];
print_r($headers);
$message = $msg['message'];
print_r($message);
}
}
microsoft.php
use Microsoft\Graph\Graph;
use Microsoft\Graph\Model;
class Azure {
public $tokenPath;
public $client;
public $graph;
public $token;
public function __construct(){
global $rootPath, $config;
$this->tokenPath = $rootPath.'assets/files/tokens/ms.json';
$this->client = new \League\OAuth2\Client\Provider\GenericProvider([
'clientId' => $config['vendor']['microsoft']['client'],
'clientSecret' => $config['vendor']['microsoft']['secret'],
'redirectUri' => $config['vendor']['microsoft']['redirect_uri'],
'urlAuthorize' => $config['vendor']['microsoft']['authority'].$config['vendor']['microsoft']['auth_endpoint'],
'urlAccessToken' => $config['vendor']['microsoft']['authority'].$config['vendor']['microsoft']['token_endpoint'],
'urlResourceOwnerDetails' => '',
'scopes' => $config['vendor']['microsoft']['scopes']
]);
$this->graph = new Graph();
}
public function getClient(){
return $this->client;
}
public function getGraph($token){
try{
$this->graph->setAccessToken($token);
return $this->graph;
}catch(Exception $ex){
echo $ex->getMessage();
}
}
public function obtainToken($accessCode){
try {
$this->token = $this->client->getAccessToken('authorization_code', [
'code' => $accessCode
]);
return $this->token;
}catch (League\OAuth2\Client\Provider\Exception\IdentityProviderException $e) {
exit('ERROR getting tokens: '.$e->getMessage());
}
}
public function refreshToken(){
global $rootPath;
$string = file_get_contents($this->tokenPath);
$token = json_decode($string, true);
$newToken = $this->client->getAccessToken('refresh_token', [
'refresh_token' => $token['refresh_token']
]);
$this->token = $newToken;
$tokenData = $this->token->jsonSerialize();
unlink($this->tokenPath);
saveFile($this->tokenPath, json_encode($tokenData));
return $this->token;
}
public function getToken(){
if($this->token !== null){
$now = time() + 300;
if($this->token->getExpires() <= $now){
$this->refreshToken();
}
return $this->token;
}else{
return $this->refreshToken();
}
}
public function getMessages(){
try{
$params = array(
"\$select" => "id",
"\$filter" => "isRead ne true",
"\$count" => "true"
);
$getMessagesUrl = '/me/mailfolders/inbox/messages?'.http_build_query($params);
$messageList = $this->graph->createRequest('GET', $getMessagesUrl)
->setReturnType(Model\Message::class)
->execute();
unset($params);
$messages = [];
foreach($messageList as $msg){
$msgId = $msg->getId();
$params = array(
"\$select" => "internetMessageHeaders"
);
$getMessageHeadersUrl = '/me/messages/'.$msgId.'/?'.http_build_query($params);
$headerObj = $this->graph->createRequest('GET', $getMessageHeadersUrl)
->setReturnType(Model\Message::class)
->execute();
$headers = [];
$internetMessageHeaders = $headerObj->getInternetMessageHeaders();
foreach($internetMessageHeaders as $header){
$headers[$header['name']] = $header['value'];
}
$params = array(
"\$select" => "*"
);
$getMessageUrl = '/me/messages/'.$msgId.'/';
$message = $this->graph->createRequest('GET', $getMessageUrl)
->setReturnType(Model\Message::class)
->execute();
$messages[] = array(
'headers' => $headers,
'message' => $message
);
}
return $messages;
}catch(Exception $ex){
if(stristr($ex->getMessage(), 'Access token has expired.')){
$this->refreshToken();
}
}
}
}
我不明白我在做什么错。如何在不中断工作流程的情况下刷新令牌?