In diesem Dokument wird OAuth 2.0 erläutert. Außerdem erfahren Sie, wann Sie es verwenden, wie Sie Client-IDs erhalten und wie Sie es mit der Google API-Clientbibliothek für .NET verwenden.
OAuth 2.0-Protokoll
OAuth 2.0 ist das Autorisierungsprotokoll, das von Google APIs verwendet wird. Lesen Sie die folgenden Links, um sich mit dem Protokoll vertraut zu machen:
Client-IDs und -Secrets erwerben
Sie können Client-IDs und Secrets in der Google API Console abrufen. Es gibt verschiedene Arten von Client-IDs. Achte darauf, den richtigen Typ für deine Anwendung zu ermitteln:
- Client-IDs von Webanwendungen
- Client-IDs von installierten Anwendungen
- Client-IDs des Dienstkontos
In jedem der Code-Snippets unten (außer dem Dienstkonto) müssen Sie den Clientschlüssel herunterladen und als client_secrets.json
in Ihrem Projekt speichern.
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. Danach erhalten Sie eine Fehlermeldung, wenn Sie versuchen, es zu verwenden.
UserCredential
und AuthorizationCodeFlow
sorgen dafür, dass das Token automatisch aktualisiert wird. Dies bedeutet einfach, dass ein neues Zugriffstoken abgerufen wird.
Dazu verwenden Sie ein langlebiges Aktualisierungstoken, das Sie zusammen mit dem Zugriffstoken erhalten, wenn Sie den Parameter access_type=offline
während des Autorisierungscodeflusses verwenden.
In den meisten Anwendungen wird empfohlen, das Zugriffstoken und das Aktualisierungstoken der Anmeldedaten im nichtflüchtigen Speicher zu speichern. Andernfalls müssen Sie dem Endnutzer stündlich eine Autorisierungsseite im Browser anzeigen, da das Zugriffstoken eine Stunde nach Erhalt der Anfrage abläuft.
Damit das Zugriffs- und Aktualisierungstoken weiterhin vorhanden ist, kannst du eine eigene Implementierung von IDataStore
bereitstellen oder eine der folgenden Implementierungen der Bibliothek verwenden:
-
FileDataStore
für .NET sorgt dafür, dass die Anmeldedaten in einer Datei beibehalten werden.
ServiceAccountCredential
ServiceAccountCredential
ähnelt UserCredential
, dient jedoch einem anderen Zweck.
Google OAuth 2.0 unterstützt Interaktionen zwischen Servern, zum Beispiel zwischen einer Webanwendung und Google Cloud Storage.
Die anfragende Anwendung muss ihre eigene Identität nachweisen, um Zugriff auf eine API zu erhalten. Ein Endnutzer muss dabei 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 so registrieren können:
- Da der Antwort-Handler nicht erfolgreich ist, wird das Token aktualisiert, wenn er den HTTP-Statuscode
401
erhält. - Ein Abfangprogramm, um den
Authorization
-Header bei jeder Anfrage abzufangen.
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 neueUserCredential
-Instanz erstellt. Diese statische Methode erhält Folgendes:- Der Clientschlüssel (oder ein Stream zum Clientschlüssel).
- Die erforderlichen Bereiche.
- Die Nutzerkennung.
- Das Abbruchtoken zum Abbrechen eines Vorgangs.
- Ein optionaler Datenspeicher. Wenn kein Datenspeicher angegeben wird, ist die Standardeinstellung eine
FileDataStore
mit einem StandardordnerGoogle.Apis.Auth
. Der Ordner wird inEnvironment.SpecialFolder.ApplicationData
erstellt.
-
Die
UserCredential
, die von dieser Methode zurückgegeben wird, wird alsHttpClientInitializer
fürBooksService
(mit dem Initialisierer) festgelegt. Wie oben erläutert, implementiertUserCredential
einen HTTP-Client-Initialisierer. -
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 unser Beispiel für Bücher 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 meisten Google-basierten OAuth 2.0-Szenarien in ASP.NET Core 3-Anwendungen. Es implementiert einen Google-spezifischen OpenIdConnect
-Authentifizierungs-Handler. Es unterstützt die inkrementelle Authentifizierung und definiert eine injizierbare IGoogleAuthProvider
, um Google-Anmeldedaten bereitzustellen, 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-Standardanwendung.
Wenn Sie diese Anleitung als Anleitung durchgehen möchten, benötigen Sie Ihre eigene ASP.NET Core 3-Anwendung und führen diese Schritte als Voraussetzung aus.
Voraussetzungen
- Installieren Sie das Paket Google.Apis.Auth.AspNetCore3.
- Wir verwenden die Google Drive API. Deshalb 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 für die Autorisierung, mit denen Ihre App für Google identifiziert wird. Erstellen Sie anhand dieser Anleitung Autorisierungsanmeldedaten und laden Sie die Datei
client_secrets.json
herunter. Zwei Highlights:- Beachten Sie, dass der Anmeldedatentyp Webanwendung sein muss.
- Zum Ausführen dieser Anwendung musst du 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 Verwendungsanweisung 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 die Client-ID und den Clientschlüssel mit den Werten aus der Dateiclient_secrets.json
. Sie können diese Werte direkt aus der JSON-Datei laden oder sie auf andere sichere Weise speichern. Die MethodeClientInfo.Load
im Projekt „Google.Apis.Auth.AspNetCore3.IntegrationTests“ zeigt 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 der Methode
Startup.Configure
die ASP.NET Core 3-Authentifizierungs- und Autorisierungs-Middleware-Komponenten sowie HTTPS-Weiterleitungen in die Pipeline ein:public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { ... app.UseHttpsRedirection(); ... app.UseAuthentication(); app.UseAuthorization(); ... }
Mit den Anmeldedaten des Nutzers in seinem Namen auf Google APIs zugreifen
Sie können Ihren Controllern jetzt Aktionsmethoden hinzufügen, für die Nutzeranmeldedaten erforderlich sind, um in ihrem Namen auf Google APIs zugreifen zu können. Das folgende Snippet zeigt, wie die Dateien im authentifizierten Google Drive-Konto des Nutzers aufgelistet werden. Beachten Sie vor allem zwei Dinge:
-
Der Nutzer muss nicht nur authentifiziert sein, sondern auch Ihrer App den Bereich
https://www.googleapis.com/auth/drive.readonly
gewährt haben, den Sie über das AttributGoogleScopedAuthorize
angeben. -
Wir verwenden den Standardabhängigkeitsinjektions-Mechanismus von ASP.NET Core 3, um einen
IGoogleAuthProvider
zu erhalten, anhand dessen wir die Anmeldedaten des Nutzers abrufen.
Der Code:
-
Fügen Sie dem Controller zuerst die folgenden Anweisungen 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 so hinzu (und begleiten 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. Sehen Sie sich HomeController.cs
des Projekts „Google.Apis.Auth.AspNetCore3.IntegrationTests“ an, um zu erfahren, wie Sie Folgendes erreichen können:
- Nur Nutzerauthentifizierung ohne bestimmte Bereiche
- Abmeldefunktion
- Inkrementelle Autorisierung über Code. Das obige Snippet zeigt die inkrementelle Autorisierung über Attribute.
- Derzeit 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 fast abläuft, und es automatisch aktualisiert.
Webanwendungen (ASP.NET MVC)
Google APIs unterstützen OAuth 2.0 für Webserveranwendungen.
Damit der folgende Code erfolgreich ausgeführt werden kann, musst du deinem Projekt zuerst in der Google API Console einen Weiterleitungs-URI hinzufügen.
Da Sie FlowMetadata
und die Standardeinstellungen verwenden, legen Sie den Weiterleitungs-URI auf your_site/AuthCallback/IndexAsync
fest.
So finden Sie die Weiterleitungs-URIs für Ihre OAuth 2.0-Anmeldedaten:
- Öffnen Sie in der API Console die Seite „Anmeldedaten“.
- Falls noch nicht geschehen, erstellen Sie Ihre OAuth 2.0-Anmeldedaten. Klicken Sie dazu auf Anmeldedaten erstellen > OAuth-Client-ID.
- Nachdem Sie Ihre Anmeldedaten erstellt haben, können Sie die Weiterleitungs-URLs aufrufen oder bearbeiten. Klicken Sie dazu im Bereich OAuth 2.0-Client-IDs auf die Client-ID (für eine Webanwendung).
Fügen Sie nach dem Erstellen eines neuen Webanwendungsprojekts in Ihrer IDE das richtige Google.Apis
-NuGet-Paket für Drive, YouTube oder einen anderen Dienst hinzu, den Sie verwenden möchten. Fügen Sie dann das Paket Google.Apis.Auth.MVC hinzu.
Der folgende Code zeigt eine ASP.NET MVC-Anwendung, die einen Google API-Dienst abfragt.
-
Fügen Sie Ihre eigene Implementierung von
FlowMetadata
hinzu.using System; using System.Web.Mvc; using Google.Apis.Auth.OAuth2; using Google.Apis.Auth.OAuth2.Flows; using Google.Apis.Auth.OAuth2.Mvc; using Google.Apis.Drive.v2; using Google.Apis.Util.Store; namespace Google.Apis.Sample.MVC4 { public class AppFlowMetadata : FlowMetadata { private static readonly IAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer { ClientSecrets = new ClientSecrets { ClientId = "PUT_CLIENT_ID_HERE", ClientSecret = "PUT_CLIENT_SECRET_HERE" }, Scopes = new[] { DriveService.Scope.Drive }, DataStore = new FileDataStore("Drive.Api.Auth.Store") }); public override string GetUserId(Controller controller) { // In this sample we use the session to store the user identifiers. // That's not the best practice, because you should have a logic to identify // a user. You might want to use "OpenID Connect". // You can read more about the protocol in the following link: // https://developers.google.com/accounts/docs/OAuth2Login. var user = controller.Session["user"]; if (user == null) { user = Guid.NewGuid(); controller.Session["user"] = user; } return user.ToString(); } public override IAuthorizationCodeFlow Flow { get { return flow; } } } }
FlowMetadata
ist eine abstrakte Klasse, die Ihre eigene Logik zum Abrufen der Nutzerkennung und der von Ihnen verwendetenIAuthorizationCodeFlow
enthält.Im Beispielcode oben wird ein neuer
GoogleAuthorizationCodeFlow
mit den richtigen Bereichen, Clientschlüsseln und dem Datenspeicher erstellt. Sie können auch eine eigene Implementierung vonIDataStore
hinzufügen, z. B. eine Version, dieEntityFramework
verwendet. -
Implementieren Sie Ihren eigenen Controller, der einen Google API-Dienst verwendet.
Im folgenden Beispiel wird ein
DriveService
verwendet:using System.Linq; using System.Threading; using System.Threading.Tasks; using System.Web.Mvc; using Google.Apis.Auth.OAuth2.Mvc; using Google.Apis.Drive.v2; using Google.Apis.Services; using Google.Apis.Sample.MVC4; namespace Google.Apis.Sample.MVC4.Controllers { public class HomeController : Controller { public async Task<ActionResult> IndexAsync(CancellationToken cancellationToken) { var result = await new AuthorizationCodeMvcApp(this, new AppFlowMetadata()). AuthorizeAsync(cancellationToken); if (result.Credential != null) { var service = new DriveService(new BaseClientService.Initializer { HttpClientInitializer = result.Credential, ApplicationName = "ASP.NET MVC Sample" }); // YOUR CODE SHOULD BE HERE.. // SAMPLE CODE: var list = await service.Files.List().ExecuteAsync(); ViewBag.Message = "FILE COUNT IS: " + list.Items.Count(); return View(); } else { return new RedirectResult(result.RedirectUri); } } } }
-
Implementieren Sie Ihren eigenen Callback-Controller. Die Implementierung sollte in etwa so aussehen:
using Google.Apis.Sample.MVC4; namespace Google.Apis.Sample.MVC4.Controllers { public class AuthCallbackController : Google.Apis.Auth.OAuth2.Mvc.Controllers.AuthCallbackController { protected override Google.Apis.Auth.OAuth2.Mvc.FlowMetadata FlowData { get { return new AppFlowMetadata(); } } } }
Dienstkonto
Google APIs unterstützen auch Dienstkonten. Anders als in einem 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 Anfrage für ein Zugriffstoken mithilfe eines privaten Schlüssels, der aus der Google API Console heruntergeladen wurde. Nachdem Sie eine neue Client-ID erstellt haben, sollten Sie einen Anwendungstyp „Dienstkonto“ auswählen und dann den privaten Schlüssel herunterladen. Sehen Sie sich unser Beispiel für ein Dienstkonto 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 wird ein ServiceAccountCredential
erstellt.
Die erforderlichen Bereiche sind festgelegt und es gibt einen Aufruf an FromCertificate
, der den privaten Schlüssel aus dem angegebenen X509Certificate2
lädt.
Wie bei jedem anderen Beispielcode sind die Anmeldedaten auf HttpClientInitializer
gesetzt.