无缝刷新Microsoft图形API令牌

时间:2019-04-25 05:40:31

标签: php microsoft-graph

我正在尝试使用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();
            }
        }
    }
}

我不明白我在做什么错。如何在不中断工作流程的情况下刷新令牌?

0 个答案:

没有答案