без проблем обновить майкрософт график API-токен - PullRequest
0 голосов
/ 25 апреля 2019

Я пытаюсь создать (несколько) бесшовное приложение на 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();
            }
        }
    }
}

Я не понимаю, что я делаю неправильно.Как я могу обновить токен, не прерывая рабочий процесс?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...