OAuth 2.0

In diesem Dokument wird beschrieben, wann und wie OAuth 2.0 verwendet wird, wie Client-IDs abgerufen werden und wie OAuth 2.0 mit der Google API-Clientbibliothek für .NET verwendet wird.

OAuth 2.0-Protokoll

OAuth 2.0 ist das Autorisierungsprotokoll, das von Google APIs verwendet wird. Machen Sie sich unter den folgenden Links mit dem Protokoll vertraut:

Client-IDs und Secrets abrufen

Sie können Client-IDs und Secrets in der Google API Console abrufen. Es gibt verschiedene Arten von Client-IDs. Achten Sie daher darauf, den richtigen Typ für Ihre Anwendung zu verwenden:

Laden Sie in jedem der folgenden Code-Snippets (außer dem Dienstkonto 1) den Clientschlüssel herunter und speichern Sie ihn als client_secrets.json in Ihrem Projekt.

Anmeldedaten

Nutzeranmeldedaten

UserCredential ist eine Thread-sichere Hilfsklasse für die Verwendung eines Zugriffstokens für den Zugriff auf geschützte Ressourcen. Ein Zugriffstoken läuft in der Regel nach einer Stunde ab. Nach dem Versuch, es zu verwenden, erhalten Sie eine Fehlermeldung.

UserCredential und AuthorizationCodeFlow sorgen dafür, dass das Token automatisch aktualisiert wird, was einfach bedeutet, dass ein neues Zugriffstoken abgerufen wird. Dazu wird ein langlebiges Aktualisierungstoken verwendet, das Sie zusammen mit dem Zugriffstoken erhalten, wenn Sie während des Autorisierungscode-Vorgangs den Parameter access_type=offline verwenden.

In den meisten Anwendungen empfiehlt es sich, das Zugriffstoken und das Aktualisierungstoken der Anmeldedaten im nichtflüchtigen Speicher zu speichern. Andernfalls müssen Sie dem Endnutzer jede Stunde eine Autorisierungsseite im Browser anzeigen, da das Zugriffstoken eine Stunde nach Erhalt abläuft.

Damit die Zugriffs- und Aktualisierungstokens dauerhaft bestehen, können Sie Ihre eigene Implementierung von IDataStore oder eine der folgenden von der Bibliothek bereitgestellten Implementierungen verwenden:

  • FileDataStore für .NET sorgt dafür, dass die Anmeldedaten in einer Datei persistent bleiben.

ServiceAccountCredential

ServiceAccountCredential ähnelt UserCredential, erfüllt jedoch einen anderen Zweck. Google OAuth 2.0 unterstützt Interaktionen zwischen Servern, beispielsweise zwischen einer Webanwendung und Google Cloud Storage. Die anfragende Anwendung muss ihre eigene Identität nachweisen, um Zugriff auf eine API zu erhalten, und ein Endnutzer muss nicht beteiligt sein. ServiceAccountCredential speichert einen privaten Schlüssel, mit dem eine Anfrage zum Abrufen eines neuen Zugriffstokens signiert wird.

Sowohl UserCredential als auch ServiceAccountCredential implementieren IConfigurableHttpClientInitializer, sodass Sie jedes davon als registrieren können:

  • Ein fehlgeschlagener Antwort-Handler. Daher wird das Token aktualisiert, wenn es den HTTP-Statuscode 401 empfängt.
  • Ein Interceptor, der den Header Authorization bei jeder Anfrage abfängt.

Installierte Apps

Beispielcode mit der Books API:

using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;

using Google.Apis.Auth.OAuth2;
using Google.Apis.Books.v1;
using Google.Apis.Books.v1.Data;
using Google.Apis.Services;
using Google.Apis.Util.Store;

namespace Books.ListMyLibrary
{
    /// <summary>
    /// Sample which demonstrates how to use the Books API.
    /// https://developers.google.com/books/docs/v1/getting_started
    /// <summary>
    internal class Program
    {
        [STAThread]
        static void Main(string[] args)
        {
            Console.WriteLine("Books API Sample: List MyLibrary");
            Console.WriteLine("================================");
            try
            {
                new Program().Run().Wait();
            }
            catch (AggregateException ex)
            {
                foreach (var e in ex.InnerExceptions)
                {
                    Console.WriteLine("ERROR: " + e.Message);
                }
            }
            Console.WriteLine("Press any key to continue...");
            Console.ReadKey();
        }

        private async Task Run()
        {
            UserCredential credential;
            using (var stream = new FileStream("client_secrets.json", FileMode.Open, FileAccess.Read))
            {
                credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
                    GoogleClientSecrets.Load(stream).Secrets,
                    new[] { BooksService.Scope.Books },
                    "user", CancellationToken.None, new FileDataStore("Books.ListMyLibrary"));
            }

            // Create the service.
            var service = new BooksService(new BaseClientService.Initializer()
                {
                    HttpClientInitializer = credential,
                    ApplicationName = "Books API Sample",
                });

            var bookshelves = await service.Mylibrary.Bookshelves.List().ExecuteAsync();
            ...
        }
    }
}
  
  • In diesem Beispielcode wird durch Aufrufen der Methode GoogleWebAuthorizationBroker.AuthorizeAsync eine neue UserCredential-Instanz erstellt. Diese statische Methode ruft Folgendes ab:

    • Der Clientschlüssel (oder ein Stream zum Clientschlüssel).
    • Die erforderlichen Bereiche.
    • Die Nutzerkennung.
    • Das Stornierungstoken zum Abbrechen eines Vorgangs.
    • Ein optionaler Datenspeicher. Wenn der Datenspeicher nicht angegeben ist, ist der Standardwert ein FileDataStore mit einem Standardordner Google.Apis.Auth. Der Ordner wird in Environment.SpecialFolder.ApplicationData erstellt.
  • Die von dieser Methode zurückgegebene UserCredential wird als HttpClientInitializer für BooksService festgelegt (unter Verwendung des Initialisierers). Wie oben erläutert, implementiert UserCredential einen HTTP-Clientinitialisierer.

  • Im Beispielcode oben werden die Clientschlüsselinformationen aus einer Datei geladen. Sie können aber auch Folgendes tun:

    credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
        new ClientSecrets
        {
            ClientId = "PUT_CLIENT_ID_HERE",
            ClientSecret = "PUT_CLIENT_SECRETS_HERE"
        },
        new[] { BooksService.Scope.Books },
        "user",
        CancellationToken.None,
        new FileDataStore("Books.ListMyLibrary"));
          

Sehen Sie sich unsere Leseprobe an.

Webanwendungen (ASP.NET Core 3)

Google APIs unterstützen OAuth 2.0 für Webserveranwendungen.

Google.Apis.Auth.AspNetCore3 ist die empfohlene Bibliothek für die Verwendung der meisten Google-basierten OAuth 2.0-Szenarien in ASP.NET Core 3-Anwendungen. Es implementiert einen Google-spezifischen Auth-Handler OpenIdConnect. Er unterstützt die inkrementelle Authentifizierung und definiert ein injizierbares IGoogleAuthProvider, um Google-Anmeldedaten anzugeben, die mit Google APIs verwendet werden können.

In diesem Abschnitt wird beschrieben, wie Sie Google.Apis.Auth.AspNetCore3 konfigurieren und verwenden. Der hier gezeigte Code basiert auf Google.Apis.Auth.AspNetCore3.IntegrationTests, einer voll funktionsfähigen ASP.NET Core 3-Standardanwendung.

Wenn Sie dieser Dokumentation als Tutorial folgen möchten, benötigen Sie eine eigene ASP.NET Core 3-Anwendung und müssen diese Schritte als Voraussetzung ausführen.

Voraussetzungen

  • Installieren Sie das Paket Google.Apis.Auth.AspNetCore3.
  • Da wir die Google Drive API verwenden, müssen Sie auch das Paket Google.Apis.Drive.v3 installieren.
  • Erstellen Sie ein Google Cloud-Projekt, falls Sie noch keines haben. Folgen Sie dazu dieser Anleitung. Dies ist das Projekt, mit dem Ihre App identifiziert wird.
  • Aktivieren Sie die Google Drive API. Folgen Sie dieser Anleitung, um APIs zu aktivieren.
  • Erstellen Sie Anmeldedaten, mit denen Ihre App gegenüber Google identifiziert werden kann. Folgen Sie dieser Anleitung, um Anmeldedaten für die Autorisierung zu erstellen und die Datei client_secrets.json herunterzuladen. Zwei Highlights:
    • Der Anmeldedatentyp muss Webanwendung lauten.
    • Zum Ausführen dieser Anwendung müssen Sie nur den Weiterleitungs-URI https://localhost:5001/signin-oidc hinzufügen.

Anwendung für die Verwendung von Google.Apis.Auth.AspNetCore3 konfigurieren

Google.Apis.Auth.AspNetCore3 ist in der Klasse Startup oder einer ähnlichen Alternative konfiguriert, die Sie möglicherweise verwenden. Die folgenden Snippets werden aus Startup.cs im Projekt Google.Apis.Auth.AspNetCore3.IntegrationTests extrahiert.

  • Fügen Sie der Datei Startup.cs die folgende Nutzungsdirektive hinzu.
    using Google.Apis.Auth.AspNetCore3;
  • Fügen Sie in der Methode Startup.ConfigureServices den folgenden Code hinzu und ändern Sie die Platzhalter für Client-ID und Clientschlüssel durch die in der Datei client_secrets.json enthaltenen Werte. Sie können diese Werte direkt aus der JSON-Datei laden oder auf eine andere sichere Weise speichern. In der Methode ClientInfo.Load im Projekt Google.Apis.Auth.AspNetCore3.IntegrationTests finden Sie ein Beispiel zum Laden dieser Werte direkt aus der JSON-Datei.
    public void ConfigureServices(IServiceCollection services)
    {
        ...
    
        // This configures Google.Apis.Auth.AspNetCore3 for use in this app.
        services
            .AddAuthentication(o =>
            {
                // This forces challenge results to be handled by Google OpenID Handler, so there's no
                // need to add an AccountController that emits challenges for Login.
                o.DefaultChallengeScheme = GoogleOpenIdConnectDefaults.AuthenticationScheme;
                // This forces forbid results to be handled by Google OpenID Handler, which checks if
                // extra scopes are required and does automatic incremental auth.
                o.DefaultForbidScheme = GoogleOpenIdConnectDefaults.AuthenticationScheme;
                // Default scheme that will handle everything else.
                // Once a user is authenticated, the OAuth2 token info is stored in cookies.
                o.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            })
            .AddCookie()
            .AddGoogleOpenIdConnect(options =>
            {
                options.ClientId = {YOUR_CLIENT_ID};
                options.ClientSecret = {YOUR_CLIENT_SECRET};
            });
    }
          
  • Fügen Sie in der Methode Startup.Configure der Pipeline ASP.NET Core 3-Authentifizierungs- und Autorisierungs-Middleware-Komponenten sowie HTTPS-Weiterleitungen hinzu:
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        ...
        app.UseHttpsRedirection();
        ...
    
        app.UseAuthentication();
        app.UseAuthorization();
    
        ...
    }
          

Die Anmeldedaten des Nutzers verwenden, um in seinem Namen auf Google APIs zuzugreifen

Sie können jetzt Aktionsmethoden zu Ihren Controllern hinzufügen, die Nutzeranmeldedaten benötigen, um in ihrem Namen auf Google APIs zuzugreifen. Das folgende Snippet zeigt, wie die Dateien im Google Drive-Konto des authentifizierten Nutzers aufgelistet werden. Beachten Sie vor allem zwei Dinge:

  • Der Nutzer muss nicht nur authentifiziert sein, sondern Ihrer Anwendung auch den Bereich https://www.googleapis.com/auth/drive.readonly gewährt haben, den Sie über das Attribut GoogleScopedAuthorize angeben.
  • Wir verwenden den Standardmechanismus für Abhängigkeitsinjektionen von ASP.NET Core 3, um ein IGoogleAuthProvider zu erhalten, mit dem wir die Anmeldedaten des Nutzers abrufen.

Der Code:

  • Füge zuerst die folgenden Nutzungsanweisungen deinem Controller hinzu.
    using Google.Apis.Auth.AspNetCore3;
    using Google.Apis.Auth.OAuth2;
    using Google.Apis.Drive.v3;
    using Google.Apis.Services;
          
  • Fügen Sie die Controller-Aktion wie unten beschrieben hinzu (und ergänzen Sie sie mit einer einfachen Ansicht, die ein IList<string>-Modell empfängt):
    /// <summary>
    /// Lists the authenticated user's Google Drive files.
    /// Specifying the <see cref="GoogleScopedAuthorizeAttribute"> will guarantee that the code
    /// executes only if the user is authenticated and has granted the scope specified in the attribute
    /// to this application.
    /// </summary>
    /// <param name="auth">The Google authorization provider.
    /// This can also be injected on the controller constructor.</param>
    [GoogleScopedAuthorize(DriveService.ScopeConstants.DriveReadonly)]
    public async Task<IActionResult> DriveFileList([FromServices] IGoogleAuthProvider auth)
    {
        GoogleCredential cred = await auth.GetCredentialAsync();
        var service = new DriveService(new BaseClientService.Initializer
        {
            HttpClientInitializer = cred
        });
        var files = await service.Files.List().ExecuteAsync();
        var fileNames = files.Files.Select(x => x.Name).ToList();
        return View(fileNames);
    }
          

Und das sind die Grundlagen. Unter HomeController.cs aus dem Projekt „Google.Apis.Auth.AspNetCore3.IntegrationTests“ finden Sie Informationen dazu, wie Sie das erreichen können:

  • Nur Nutzerauthentifizierung ohne bestimmte Bereiche
  • Abmeldefunktion
  • Inkrementelle Autorisierung über Code. Das obige Snippet zeigt die inkrementelle Autorisierung über Attribute.
  • Aktuell gewährte Bereiche untersuchen
  • Zugriffs- und Aktualisierungstokens prüfen
  • Erzwingen Sie die Aktualisierung des Zugriffstokens. Sie müssen dies nicht selbst tun, da Google.Apis.Auth.AspNetCore3 erkennt, ob das Zugriffstoken abgelaufen ist oder bald abläuft, und es automatisch aktualisiert.

Dienstkonto

Google APIs unterstützen auch Dienstkonten. Im Gegensatz zu dem Szenario, in dem eine Clientanwendung Zugriff auf die Daten eines Endnutzers anfordert, bieten Dienstkonten Zugriff auf die eigenen Daten der Clientanwendung.

Ihre Clientanwendung signiert die Anforderung eines Zugriffstokens mit einem privaten Schlüssel, der von der Google API Console heruntergeladen wurde. Nachdem Sie eine neue Client-ID erstellt haben, sollten Sie den Anwendungstyp „Dienstkonto“ auswählen. Anschließend können Sie den privaten Schlüssel herunterladen. Sehen Sie sich unser Dienstkonto-Beispiel mit der Google Plus API an.

using System;
using System.Security.Cryptography.X509Certificates;

using Google.Apis.Auth.OAuth2;
using Google.Apis.Plus.v1;
using Google.Apis.Plus.v1.Data;
using Google.Apis.Services;

namespace Google.Apis.Samples.PlusServiceAccount
{
    /// <summary>
    /// This sample demonstrates the simplest use case for a Service Account service.
    /// The certificate needs to be downloaded from the Google API Console
    /// <see cref="https://console.cloud.google.com/">
    ///   "Create another client ID..." -> "Service Account" -> Download the certificate,
    ///   rename it as "key.p12" and add it to the project. Don't forget to change the Build action
    ///   to "Content" and the Copy to Output Directory to "Copy if newer".
    /// </summary>
    public class Program
    {
        // A known public activity.
        private static String ACTIVITY_ID = "z12gtjhq3qn2xxl2o224exwiqruvtda0i";

        public static void Main(string[] args)
        {
            Console.WriteLine("Plus API - Service Account");
            Console.WriteLine("==========================");

            String serviceAccountEmail = "SERVICE_ACCOUNT_EMAIL_HERE";

            var certificate = new X509Certificate2(@"key.p12", "notasecret", X509KeyStorageFlags.Exportable);

            ServiceAccountCredential credential = new ServiceAccountCredential(
               new ServiceAccountCredential.Initializer(serviceAccountEmail)
               {
                   Scopes = new[] { PlusService.Scope.PlusMe }
               }.FromCertificate(certificate));

            // Create the service.
            var service = new PlusService(new BaseClientService.Initializer()
            {
                HttpClientInitializer = credential,
                ApplicationName = "Plus API Sample",
            });

            Activity activity = service.Activities.Get(ACTIVITY_ID).Execute();
            Console.WriteLine("  Activity: " + activity.Object.Content);
            Console.WriteLine("  Video: " + activity.Object.Attachments[0].Url);

            Console.WriteLine("Press any key to continue...");
            Console.ReadKey();
        }
    }
}

Mit dem obigen Beispielcode wird ein ServiceAccountCredential erstellt. Die erforderlichen Bereiche sind festgelegt und es wird FromCertificate aufgerufen, um den privaten Schlüssel aus der angegebenen X509Certificate2 zu laden. Wie bei allen anderen Beispielcodes sind die Anmeldedaten auf HttpClientInitializer festgelegt.