Я пытаюсь создать (несколько) бесшовное приложение на PHP, используя Microsoft Graph API.Приложение должно быть запущено через командную строку, но для начальной авторизации пользователь должен открыть 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();
}
}
}
}
Я не понимаю, что я делаю неправильно.Как я могу обновить токен, не прерывая рабочий процесс?