Google Log-in für serverseitige Apps

Wenn Sie Google-Dienste im Namen eines Nutzers verwenden möchten, wenn dieser offline ist, müssen Sie einen hybriden serverseitigen Ablauf verwenden, bei dem ein Nutzer Ihre Anwendung clientseitig mit dem JavaScript API-Client autorisiert und Sie einen speziellen Einmal-Autorisierungscode an Ihren Server senden. Ihr Server tauscht diesen einmaligen Code aus, um seine eigenen Zugriffs- und Aktualisierungstokens von Google zu erhalten, damit der Server seine eigenen API-Aufrufe durchführen kann, was auch im Offlinemodus möglich ist. Dieser einmalige Codefluss bietet Sicherheitsvorteile sowohl gegenüber einem reinen serverseitigen Ablauf als auch gegenüber dem Senden von Zugriffstokens an Ihren Server.

Der Anmeldevorgang zum Abrufen eines Zugriffstokens für Ihre serverseitige Anwendung ist unten dargestellt.

Einmalcodes bieten mehrere Sicherheitsvorteile. Mit Codes stellt Google Tokens direkt und ohne Mittler auf Ihrem Server bereit. Wir raten davon ab, gehackte Codes zu veröffentlichen. Sie sind ohne Clientschlüssel sehr schwer zu verwenden. Bewahren Sie Ihren Clientschlüssel auf.

Einmalcode-Vorgang implementieren

Die Google Log-in-Schaltfläche enthält ein Zugriffstoken und einen Autorisierungscode. Der Code ist ein Einmalcode, den dein Server mit den Google-Servern gegen ein Zugriffstoken austauschen kann.

Der folgende Beispielcode zeigt, wie der Vorgang mit einmaligem Code funktioniert.

Für die Authentifizierung von Google Log-in mit Einmalcode sind folgende Schritte erforderlich:

Schritt 1: Client-ID und Clientschlüssel erstellen

Um eine Client-ID und einen Clientschlüssel zu erstellen, erstelle ein Google API Console-Projekt, richte eine OAuth-Client-ID ein und registriere deine JavaScript-Quellen:

  1. Gehen Sie zur Google API Console.

  2. Wählen Sie aus der Drop-down-Liste für Projekte ein vorhandenes Projekt aus oder erstellen Sie ein neues, indem Sie auf Neues Projekt erstellen klicken.

  3. Wählen Sie in der Seitenleiste unter „APIs und Dienste“ die Option Anmeldedaten aus und klicken Sie dann auf Zustimmungsbildschirm konfigurieren.

    Wählen Sie eine E-Mail-Adresse aus, geben Sie einen Produktnamen an und klicken Sie auf Speichern.

  4. Wählen Sie auf dem Tab Anmeldedaten die Drop-down-Liste Anmeldedaten erstellen und dann OAuth-Client-ID aus.

  5. Wählen Sie unter Anwendungstyp die Option Webanwendung aus.

    Registrieren Sie die Quellen, aus denen Ihre Anwendung auf die Google APIs zugreifen darf. Gehen Sie dazu so vor: Ein Ursprung ist eine eindeutige Kombination aus Protokoll, Hostname und Port.

    1. Geben Sie im Feld Autorisierte JavaScript-Quellen den Ursprung Ihrer Anwendung ein. Sie können mehrere Quellen angeben, damit Ihre Anwendung in verschiedenen Protokollen, Domains oder Subdomains ausgeführt werden kann. Sie können keine Platzhalter verwenden. Im folgenden Beispiel könnte die zweite URL eine Produktions-URL sein.

      http://localhost:8080
      https://myproductionurl.example.com
      
    2. Das Feld Autorisierter Weiterleitungs-URI erfordert keinen Wert. Weiterleitungs-URIs werden nicht mit JavaScript APIs verwendet.

    3. Klicken Sie auf die Schaltfläche Erstellen.

  6. Kopieren Sie im daraufhin angezeigten Dialogfeld OAuth-Client die Client-ID. Mit der Client-ID kann deine App auf aktivierte Google APIs zugreifen.

Schritt 2: Google-Plattformbibliothek in Ihre Seite einbinden

Fügen Sie die folgenden Skripts hinzu, die eine anonyme Funktion veranschaulichen, die ein Skript in das DOM dieser index.html-Webseite einfügt.

<!-- The top of file index.html -->
<html itemscope itemtype="http://schema.org/Article">
<head>
  <!-- BEGIN Pre-requisites -->
  <script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js">
  </script>
  <script src="https://apis.google.com/js/client:platform.js?onload=start" async defer>
  </script>
  <!-- END Pre-requisites -->

Schritt 3: GoogleAuth-Objekt initialisieren

Laden Sie die auth2-Bibliothek und rufen Sie gapi.auth2.init() auf, um das Objekt GoogleAuth zu initialisieren. Geben Sie die Client-ID und die Bereiche an, die beim Aufrufen von init() angefordert werden sollen.

<!-- Continuing the <head> section -->
  <script>
    function start() {
      gapi.load('auth2', function() {
        auth2 = gapi.auth2.init({
          client_id: 'YOUR_CLIENT_ID.apps.googleusercontent.com',
          // Scopes to request in addition to 'profile' and 'email'
          //scope: 'additional_scope'
        });
      });
    }
  </script>
</head>
<body>
  <!-- ... -->
</body>
</html>

Schritt 4: Anmeldeschaltfläche zu Ihrer Seite hinzufügen

Fügen Sie Ihrer Webseite die Anmeldeschaltfläche hinzu und fügen Sie einen Klick-Handler hinzu, um grantOfflineAccess() aufzurufen und den Vorgang mit Einmalcode zu starten.

<!-- Add where you want your sign-in button to render -->
<!-- Use an image that follows the branding guidelines in a real app -->
<button id="signinButton">Sign in with Google</button>
<script>
  $('#signinButton').click(function() {
    // signInCallback defined in step 6.
    auth2.grantOfflineAccess().then(signInCallback);
  });
</script>

Schritt 5: Nutzer anmelden

Der Nutzer klickt auf die Anmeldeschaltfläche und gewährt Ihrer Anwendung Zugriff auf die angeforderten Berechtigungen. Anschließend wird der Callback-Funktion, die Sie in der Methode grantOfflineAccess().then() angegeben haben, ein JSON-Objekt mit einem Autorisierungscode übergeben. Beispiel:

{"code":"4/yU4cQZTMnnMtetyFcIWNItG32eKxxxgXXX-Z4yyJJJo.4qHskT-UtugceFc0ZRONyF4z7U4UmAI"}

Schritt 6: Autorisierungscode an den Server senden

code ist Ihr einmaliger Code, den Ihr Server gegen sein eigenes Zugriffstoken und Aktualisierungstoken austauschen kann. Sie können erst dann ein Aktualisierungstoken abrufen, wenn dem Nutzer ein Dialogfeld zur Autorisierung angezeigt wurde, in dem der Offlinezugriff angefordert wird. Wenn Sie das select-account prompt in Schritt 4 in OfflineAccessOptions angegeben haben, müssen Sie das Aktualisierungstoken speichern, das Sie zur späteren Verwendung abrufen, da nachfolgende Anzeigenplattformen null für das Aktualisierungstoken zurückgeben. Dieser Ablauf bietet mehr Sicherheit gegenüber dem standardmäßigen OAuth 2.0-Vorgang.

Zugriffstokens werden immer mit einem gültigen Autorisierungscode zurückgegeben.

Das folgende Skript definiert eine Callback-Funktion für die Anmeldeschaltfläche. Nach erfolgreicher Anmeldung speichert die Funktion das Zugriffstoken für die clientseitige Verwendung und sendet den Einmalcode an Ihren Server in derselben Domain.

<!-- Last part of BODY element in file index.html -->
<script>
function signInCallback(authResult) {
  if (authResult['code']) {

    // Hide the sign-in button now that the user is authorized, for example:
    $('#signinButton').attr('style', 'display: none');

    // Send the code to the server
    $.ajax({
      type: 'POST',
      url: 'http://example.com/storeauthcode',
      // Always include an `X-Requested-With` header in every AJAX request,
      // to protect against CSRF attacks.
      headers: {
        'X-Requested-With': 'XMLHttpRequest'
      },
      contentType: 'application/octet-stream; charset=utf-8',
      success: function(result) {
        // Handle or verify the server response.
      },
      processData: false,
      data: authResult['code']
    });
  } else {
    // There was an error.
  }
}
</script>

Schritt 7: Autorisierungscode gegen Zugriffstoken austauschen

Tauschen Sie den Autorisierungscode auf dem Server gegen Zugriffs- und Aktualisierungstoken aus. Verwenden Sie das Zugriffstoken, um Google APIs im Namen des Nutzers aufzurufen. Optional können Sie das Aktualisierungstoken speichern, um nach Ablauf des Zugriffstokens ein neues Zugriffstoken zu erhalten.

Wenn Sie den Profilzugriff angefordert haben, erhalten Sie auch ein ID-Token, das die grundlegenden Profilinformationen für den Nutzer enthält.

Beispiel:

Java
// (Receive authCode via HTTPS POST)


if (request.getHeader("X-Requested-With") == null) {
  // Without the `X-Requested-With` header, this request could be forged. Aborts.
}

// Set path to the Web application client_secret_*.json file you downloaded from the
// Google API Console: https://console.cloud.google.com/apis/credentials
// You can also find your Web application client ID and client secret from the
// console and specify them directly when you create the GoogleAuthorizationCodeTokenRequest
// object.
String CLIENT_SECRET_FILE = "/path/to/client_secret.json";

// Exchange auth code for access token
GoogleClientSecrets clientSecrets =
    GoogleClientSecrets.load(
        JacksonFactory.getDefaultInstance(), new FileReader(CLIENT_SECRET_FILE));
GoogleTokenResponse tokenResponse =
          new GoogleAuthorizationCodeTokenRequest(
              new NetHttpTransport(),
              JacksonFactory.getDefaultInstance(),
              "https://oauth2.googleapis.com/token",
              clientSecrets.getDetails().getClientId(),
              clientSecrets.getDetails().getClientSecret(),
              authCode,
              REDIRECT_URI)  // Specify the same redirect URI that you use with your web
                             // app. If you don't have a web version of your app, you can
                             // specify an empty string.
              .execute();

String accessToken = tokenResponse.getAccessToken();

// Use access token to call API
GoogleCredential credential = new GoogleCredential().setAccessToken(accessToken);
Drive drive =
    new Drive.Builder(new NetHttpTransport(), JacksonFactory.getDefaultInstance(), credential)
        .setApplicationName("Auth Code Exchange Demo")
        .build();
File file = drive.files().get("appfolder").execute();

// Get profile info from ID token
GoogleIdToken idToken = tokenResponse.parseIdToken();
GoogleIdToken.Payload payload = idToken.getPayload();
String userId = payload.getSubject();  // Use this value as a key to identify a user.
String email = payload.getEmail();
boolean emailVerified = Boolean.valueOf(payload.getEmailVerified());
String name = (String) payload.get("name");
String pictureUrl = (String) payload.get("picture");
String locale = (String) payload.get("locale");
String familyName = (String) payload.get("family_name");
String givenName = (String) payload.get("given_name");
Python
from apiclient import discovery
import httplib2
from oauth2client import client

# (Receive auth_code by HTTPS POST)


# If this request does not have `X-Requested-With` header, this could be a CSRF
if not request.headers.get('X-Requested-With'):
    abort(403)

# Set path to the Web application client_secret_*.json file you downloaded from the
# Google API Console: https://console.cloud.google.com/apis/credentials
CLIENT_SECRET_FILE = '/path/to/client_secret.json'

# Exchange auth code for access token, refresh token, and ID token
credentials = client.credentials_from_clientsecrets_and_code(
    CLIENT_SECRET_FILE,
    ['https://www.googleapis.com/auth/drive.appdata', 'profile', 'email'],
    auth_code)

# Call Google API
http_auth = credentials.authorize(httplib2.Http())
drive_service = discovery.build('drive', 'v3', http=http_auth)
appfolder = drive_service.files().get(fileId='appfolder').execute()

# Get profile info from ID token
userid = credentials.id_token['sub']
email = credentials.id_token['email']