OAuth 2.0

In diesem Dokument wird beschrieben, wann 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 erhalten

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:

In jedem der folgenden Code-Snippets (außer im Dienstkonto) müssen Sie den Clientschlüssel herunterladen und in Ihrem Projekt als client_secrets.json speichern.

Anmeldedaten

Nutzeranmeldedaten

UserCredential ist eine Thread-sichere Hilfsklasse für die Verwendung eines Zugriffstokens für den Zugriff auf geschützte Ressourcen. Zugriffstokens laufen in der Regel nach einer Stunde ab. Danach erhalten Sie eine Fehlermeldung, wenn Sie versuchen, es zu verwenden.

UserCredential und AuthorizationCodeFlow übernehmen automatisch die Aktualisierung des Tokens, d. h., es wird einfach ein neues Zugriffstoken angefordert. Dazu wird ein langlebiges Aktualisierungstoken verwendet, das Sie zusammen mit dem Zugriffstoken erhalten, wenn Sie den Parameter access_type=offline während des Vorgangs mit Autorisierungscode 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 erhalten bleiben, können Sie Ihre eigene Implementierung von IDataStore oder eine der folgenden in der Bibliothek bereitgestellten Implementierungen verwenden:

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

ServiceAccountCredential

ServiceAccountCredential ähnelt UserCredential, hat aber 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 jeden der folgenden Typen registrieren können:

  • Ein fehlgeschlagener Antwort-Handler. Daher wird das Token aktualisiert, wenn es den HTTP-Statuscode 401 empfängt.
  • Ein Interceptor, der den Authorization-Header 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:

    • Den Clientschlüssel (oder ein Stream zum Clientschlüssel).
    • Die erforderlichen Bereiche.
    • Die Nutzerkennung.
    • Das Abbruchtoken für den Abbruch 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.
  • Der von dieser Methode zurückgegebene UserCredential wird als HttpClientInitializer für BooksService festgelegt (mithilfe des Initialisierers). Wie oben erläutert, implementiert UserCredential einen HTTP-Clientinitialisierer.

  • Beachten Sie, dass im obigen Beispielcode die Clientschlüsselinformationen aus einer Datei geladen werden. 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"));
          

Werfen Sie einen Blick auf unsere Leseprobe.

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 meisten Google-basierten OAuth 2.0-Szenarien in ASP.NET Core 3-Anwendungen. Es wird ein Google-spezifischer OpenIdConnect-Auth-Handler implementiert. Er unterstützt die inkrementelle Authentifizierung und definiert ein injizierbares IGoogleAuthProvider zur Bereitstellung von Google-Anmeldedaten, 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 diese Dokumentation als Tutorial verwenden möchten, benötigen Sie Ihre 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.
  • Achten Sie darauf, dass die Google Drive API aktiviert ist. 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:
    • Beachten Sie, dass der Anmeldedatentyp Webanwendung sein muss.
    • 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 folgenden Snippets werden aus Startup.cs im Projekt Google.Apis.Auth.AspNetCore3.IntegrationTests extrahiert.

  • Fügen Sie der Datei Startup.cs die folgende „using“-Anweisung 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 Werte in der Datei client_secrets.json. Sie können diese Werte direkt aus der JSON-Datei laden oder sie auf andere sichere Weise speichern. In der Methode ClientInfo.Load im Projekt Google.Apis.Auth.AspNetCore3.IntegrationTests finden Sie ein Beispiel dafür, wie diese Werte direkt aus der JSON-Datei geladen werden können.
    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();
    
        ...
    }
          

Nutzeranmeldedaten verwenden, um in ihrem Namen auf Google APIs zuzugreifen

Sie können Ihren Controllern jetzt Aktionsmethoden hinzufügen, die 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 mit dem Attribut GoogleScopedAuthorize angeben.
  • Wir verwenden den standardmäßigen Mechanismus zur Abhängigkeitsinjektion von ASP.NET Core 3, um ein IGoogleAuthProvider zu empfangen, mit dem wir die Anmeldedaten des Nutzers abrufen.

Der Code:

  • Fügen Sie Ihrem Controller zuerst die folgenden Nutzungsanweisungen hinzu.
    using Google.Apis.Auth.AspNetCore3;
    using Google.Apis.Auth.OAuth2;
    using Google.Apis.Drive.v3;
    using Google.Apis.Services;
          
  • Fügen Sie die Controlleraktion so 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. Anhand von HomeController.cs aus dem Projekt Google.Apis.Auth.AspNetCore3.IntegrationTests können Sie herausfinden, wie Sie das erreichen können:

  • Nur Nutzerauthentifizierung ohne bestimmte Bereiche
  • Abmeldefunktion
  • Inkrementelle Autorisierung über Code Im Snippet oben wird die inkrementelle Autorisierung über Attribute angezeigt.
  • Aktuell gewährte Bereiche prüfen
  • 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, den Sie aus der Google API Console heruntergeladen haben. 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 Beispielcode oben wird ein ServiceAccountCredential erstellt. Die erforderlichen Bereiche sind festgelegt und es wird FromCertificate aufgerufen, mit dem der private Schlüssel aus dem angegebenen X509Certificate2 geladen wird. Wie in jedem anderen Beispielcode werden die Anmeldedaten auf HttpClientInitializer festgelegt.