Freigeben über


Hinzufügen der Benutzerauthentifizierung zu PHP-Apps für Microsoft Graph

In diesem Artikel fügen Sie der Anwendung, die Sie unter Erstellen von PHP-Apps mit Microsoft Graph erstellt haben, die Benutzerauthentifizierung hinzu. Anschließend verwenden Sie die Microsoft Graph-Benutzer-API, um den authentifizierten Benutzer abzurufen.

Hinzufügen der Benutzerauthentifizierung

Das Microsoft Graph SDK enthält Authentifizierungsanbieter, die auf dem PHP League OAuth2-Client basieren. Für dieses Tutorial verwenden Sie jedoch den Gerätecodeflow , um Zugriffstoken zu erhalten. Die enthaltenen Authentifizierungsanbieter implementieren diesen Flow nicht, sodass Sie einen benutzerdefinierten Zugriffstokenanbieter implementieren.

Erstellen eines Zugriffstokenanbieters

Erstellen Sie eine neue Datei im Stammverzeichnis Ihres Projekts mit dem Namen DeviceCodeTokenProvider.php. Fügen Sie den folgenden Code hinzu.

<?php
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.

use GuzzleHttp\Client;
use Http\Promise\FulfilledPromise;
use Http\Promise\Promise;
use Http\Promise\RejectedPromise;
use Microsoft\Kiota\Abstractions\Authentication\AccessTokenProvider;
use Microsoft\Kiota\Abstractions\Authentication\AllowedHostsValidator;

class DeviceCodeTokenProvider implements AccessTokenProvider {

    private string $clientId;
    private string $tenantId;
    private string $scopes;
    private AllowedHostsValidator $allowedHostsValidator;
    private string $accessToken;
    private Client $tokenClient;

    public function __construct(string $clientId, string $tenantId, string $scopes) {
        $this->clientId = $clientId;
        $this->tenantId = $tenantId;
        $this->scopes = $scopes;
        $this->allowedHostsValidator = new AllowedHostsValidator();
        $this->allowedHostsValidator->setAllowedHosts([
            "graph.microsoft.com",
            "graph.microsoft.us",
            "dod-graph.microsoft.us",
            "graph.microsoft.de",
            "microsoftgraph.chinacloudapi.cn"
        ]);
        $this->tokenClient = new Client();
    }

    public function getAuthorizationTokenAsync(string $url, array $additionalAuthenticationContext = []): Promise {
        $parsedUrl = parse_url($url);
        $scheme = $parsedUrl["scheme"] ?? null;

        if ($scheme !== 'https' || !$this->getAllowedHostsValidator()->isUrlHostValid($url)) {
            return new FulfilledPromise(null);
        }

        // If we already have a user token, just return it
        // Tokens are valid for one hour, after that it needs to be refreshed
        if (isset($this->accessToken)) {
            return new FulfilledPromise($this->accessToken);
        }

        // https://learn.microsoft.com/azure/active-directory/develop/v2-oauth2-device-code
        $deviceCodeRequestUrl = 'https://login.microsoftonline.com/'.$this->tenantId.'/oauth2/v2.0/devicecode';
        $tokenRequestUrl = 'https://login.microsoftonline.com/'.$this->tenantId.'/oauth2/v2.0/token';

        // First POST to /devicecode
        $deviceCodeResponse = json_decode($this->tokenClient->post($deviceCodeRequestUrl, [
            'form_params' => [
                'client_id' => $this->clientId,
                'scope' => $this->scopes
            ]
        ])->getBody()->getContents());

        // Display the user prompt
        print($deviceCodeResponse->message.PHP_EOL);

        // Response also indicates how often to poll for completion
        // And gives a device code to send in the polling requests
        $interval = (int)$deviceCodeResponse->interval;
        $device_code = $deviceCodeResponse->device_code;

        // Do polling - if attempt times out the token endpoint
        // returns an error
        while (true) {
            sleep($interval);

            // POST to the /token endpoint
            $tokenResponse = $this->tokenClient->post($tokenRequestUrl, [
                'form_params' => [
                    'client_id' => $this->clientId,
                    'grant_type' => 'urn:ietf:params:oauth:grant-type:device_code',
                    'device_code' => $device_code
                ],
                // These options are needed to enable getting
                // the response body from a 4xx response
                'http_errors' => false,
                'curl' => [
                    CURLOPT_FAILONERROR => false
                ]
            ]);

            if ($tokenResponse->getStatusCode() == 200) {
                // Return the access_token
                $responseBody = json_decode($tokenResponse->getBody()->getContents());
                $this->accessToken = $responseBody->access_token;
                return new FulfilledPromise($responseBody->access_token);
            } else if ($tokenResponse->getStatusCode() == 400) {
                // Check the error in the response body
                $responseBody = json_decode($tokenResponse->getBody()->getContents());
                if (isset($responseBody->error)) {
                    $error = $responseBody->error;
                    // authorization_pending means we should keep polling
                    if (strcmp($error, 'authorization_pending') != 0) {
                        return new RejectedPromise(
                            new Exception('Token endpoint returned '.$error, 100));
                    }
                }
            }
        }
    }

    public function getAllowedHostsValidator(): AllowedHostsValidator {
        return $this->allowedHostsValidator;
    }
}
?>

Konfigurieren des Graph-Clients für die Benutzerauthentifizierung

Verwenden Sie nun die DeviceCodeTokenProvider -Klasse, um mithilfe des Gerätecodeflows ein Zugriffstoken anzufordern.

  1. Erstellen Sie im Stammverzeichnis Ihres Projekts eine neue Datei mit dem Namen GraphHelper.php. Fügen Sie den folgenden Code hinzu.

    <?php
    class GraphHelper {
    }
    ?>
    
  2. Fügen Sie die folgenden using Anweisungen innerhalb der PHP-Tags hinzu.

    use Microsoft\Graph\Generated\Models;
    use Microsoft\Graph\Generated\Users\Item\MailFolders\Item\Messages\MessagesRequestBuilderGetQueryParameters;
    use Microsoft\Graph\Generated\Users\Item\MailFolders\Item\Messages\MessagesRequestBuilderGetRequestConfiguration;
    use Microsoft\Graph\Generated\Users\Item\SendMail\SendMailPostRequestBody;
    use Microsoft\Graph\Generated\Users\Item\UserItemRequestBuilderGetQueryParameters;
    use Microsoft\Graph\Generated\Users\Item\UserItemRequestBuilderGetRequestConfiguration;
    use Microsoft\Graph\GraphRequestAdapter;
    use Microsoft\Graph\GraphServiceClient;
    use Microsoft\Kiota\Abstractions\Authentication\BaseBearerTokenAuthenticationProvider;
    
    require_once 'DeviceCodeTokenProvider.php';
    
  3. Fügen Sie der GraphHelper-Klasse den folgenden Code hinzu.

    private static string $clientId = '';
    private static string $tenantId = '';
    private static string $graphUserScopes = '';
    private static DeviceCodeTokenProvider $tokenProvider;
    private static GraphServiceClient $userClient;
    
    public static function initializeGraphForUserAuth(): void {
        GraphHelper::$clientId = $_ENV['CLIENT_ID'];
        GraphHelper::$tenantId = $_ENV['TENANT_ID'];
        GraphHelper::$graphUserScopes = $_ENV['GRAPH_USER_SCOPES'];
    
        GraphHelper::$tokenProvider = new DeviceCodeTokenProvider(
            GraphHelper::$clientId,
            GraphHelper::$tenantId,
            GraphHelper::$graphUserScopes);
        $authProvider = new BaseBearerTokenAuthenticationProvider(GraphHelper::$tokenProvider);
        $adapter = new GraphRequestAdapter($authProvider);
        GraphHelper::$userClient = GraphServiceClient::createWithRequestAdapter($adapter);
    }
    
  4. Ersetzen Sie die leere initializeGraph Funktion in Standard.php durch Folgendes.

    function initializeGraph(): void {
        GraphHelper::initializeGraphForUserAuth();
    }
    

Dieser Code lädt Informationen aus der ENV-Datei und initialisiert zwei Eigenschaften, ein DeviceCodeTokenProvider -Objekt und ein GraphServiceClient -Objekt. Das DeviceCodeTokenProvider -Objekt wird verwendet, um ein Zugriffstoken anzufordern, und das GraphServiceClient -Objekt wird für Aufrufe an Microsoft Graph verwendet.

Testen des Gerätecodeflows

Fügen Sie als Nächstes Code hinzu, um ein Zugriffstoken GraphHelpervon abzurufen.

  1. Fügen Sie die folgende Funktion zur GraphHelper-Klasse hinzu:

    public static function getUserToken(): string {
        return GraphHelper::$tokenProvider
            ->getAuthorizationTokenAsync('https://graph.microsoft.com')->wait();
    }
    
  2. Ersetzen Sie die leere displayAccessToken Funktion in Standard.php durch Folgendes.

    function displayAccessToken(): void {
        try {
            $token = GraphHelper::getUserToken();
            print('User token: '.$token.PHP_EOL.PHP_EOL);
        } catch (Exception $e) {
            print('Error getting access token: '.$e->getMessage().PHP_EOL.PHP_EOL);
        }
    }
    
  3. Erstellen Sie die App, und führen Sie sie aus. Geben Sie ein 1 , wenn Sie zur Eingabe einer Option aufgefordert werden. Die Anwendung zeigt eine URL und den Gerätecode an.

    $ php main.php
    
    PHP Graph Tutorial
    
    Please choose one of the following options:
    0. Exit
    1. Display access token
    2. List my inbox
    3. Send mail
    4. Make a Graph call
    1
    To sign in, use a web browser to open the page https://microsoft.com/devicelogin and
    enter the code RB2RUD56D to authenticate.
    
  4. Öffnen Sie einen Browser, und navigieren Sie zu der angezeigten URL. Geben Sie den angegebenen Code ein, und melden Sie sich an.

    Wichtig

    Achten Sie auf vorhandene Microsoft 365-Konten, die bei Ihrem Browser angemeldet sind, wenn Sie zu https://microsoft.com/deviceloginnavigieren. Verwenden Sie Browserfeatures wie Profile, Gastmodus oder privaten Modus, um sicherzustellen, dass Sie sich als das Konto authentifizieren, das Sie zu Testzwecken verwenden möchten.

  5. Kehren Sie nach Abschluss des Vorgangs zur Anwendung zurück, um das Zugriffstoken anzuzeigen.

    Tipp

    Nur zu Validierungs- und Debugzwecken können Sie Benutzerzugriffstoken (nur für Geschäfts-, Schul- oder Unikonten) decodieren, indem Sie den Onlinetokenparser von Microsoft unter verwendenhttps://jwt.ms. Die Analyse Ihres Tokens kann nützlich sein, wenn beim Aufrufen von Microsoft Graph Tokenfehler auftreten. Beispielsweise wird überprüft, ob der scp Anspruch im Token die erwarteten Microsoft Graph-Berechtigungsbereiche enthält.

Benutzer abrufen

Nachdem die Authentifizierung konfiguriert wurde, können Sie Ihren ersten Microsoft Graph-API-Aufruf durchführen. Fügen Sie Code hinzu, um den Namen und die E-Mail-Adresse des authentifizierten Benutzers abzurufen.

  1. Fügen Sie der GraphHelper-Klasse den folgenden Code hinzu.

    public static function getUser(): Models\User {
        $configuration = new UserItemRequestBuilderGetRequestConfiguration();
        $configuration->queryParameters = new UserItemRequestBuilderGetQueryParameters();
        $configuration->queryParameters->select = ['displayName','mail','userPrincipalName'];
        return GraphHelper::$userClient->me()->get($configuration)->wait();
    }
    
  2. Ersetzen Sie die leere greetUser Funktion in Standard.php durch Folgendes.

    function greetUser(): void {
        try {
            $user = GraphHelper::getUser();
            print('Hello, '.$user->getDisplayName().'!'.PHP_EOL);
    
            // For Work/school accounts, email is in Mail property
            // Personal accounts, email is in UserPrincipalName
            $email = $user->getMail();
            if (empty($email)) {
                $email = $user->getUserPrincipalName();
            }
            print('Email: '.$email.PHP_EOL.PHP_EOL);
        } catch (Exception $e) {
            print('Error getting user: '.$e->getMessage().PHP_EOL.PHP_EOL);
        }
    }
    

Wenn Sie die App jetzt ausführen, begrüßt Sie die App nach der Anmeldung mit dem Namen.

Hello, Megan Bowen!
Email: MeganB@contoso.com

Code erläutert

Betrachten Sie den Code in der getUser Funktion. Es sind nur wenige Zeilen, aber es sind einige wichtige Details zu beachten.

Zugreifen auf "me"

Die Funktion erstellt eine Anforderung an die Api zum Abrufen von Benutzern . Auf diese API kann auf zwei Arten zugegriffen werden:

GET /me
GET /users/{user-id}

In diesem Fall ruft der Code den GET /me API-Endpunkt auf. Dieser Endpunkt ist eine Verknüpfungsmethode, um den authentifizierten Benutzer abzurufen, ohne seine Benutzer-ID zu kennen.

Hinweis

Da der GET /me API-Endpunkt den authentifizierten Benutzer abruft, ist er nur für Apps verfügbar, die die Benutzerauthentifizierung verwenden. Reine App-Authentifizierungs-Apps können nicht auf diesen Endpunkt zugreifen.

Anfordern bestimmter Eigenschaften

Die Funktion verwendet den Abfrageparameter $select , um die benötigten Eigenschaften anzugeben.

Stark typisierter Rückgabetyp

Die Funktion gibt ein User Objekt zurück, das aus der JSON-Antwort der API deserialisiert wurde. Da der Code verwendet $select, verfügen nur die angeforderten Eigenschaften über Werte im zurückgegebenen User Objekt. Alle anderen Eigenschaften verfügen über Standardwerte.

Nächster Schritt