Google Log-in für serverseitige Apps

Wenn Sie Google-Dienste im Namen eines Nutzers verwenden möchten, während dieser offline ist, müssen Sie einen hybriden serverseitigen Ablauf verwenden, bei dem ein Nutzer Ihre App auf der Clientseite mithilfe des JavaScript API-Clients autorisiert und Sie einen speziellen Einmalautorisierungscode an Ihren Server senden. Ihr Server tauscht diesen Einmalcode aus, um eigene Zugriffs- und Aktualisierungstokens von Google zu erhalten, damit der Server eigene API-Aufrufe ausführen kann. Dies ist auch möglich, wenn der Nutzer offline ist. Dieser Einmalcodeablauf bietet sowohl gegenüber einem reinen serverseitigen Ablauf als auch gegenüber dem Senden von Zugriffstokens an Ihren Server Sicherheitsvorteile.

Unten ist der Anmeldevorgang zum Abrufen eines Zugriffstokens für Ihre serverseitige Anwendung dargestellt.

Einmalcodes bieten mehrere Sicherheitsvorteile. Mit Codes stellt Google Tokens direkt und ohne Mittler auf Ihrem Server bereit. Wir empfehlen zwar nicht, Codes preiszugeben, aber ohne Ihr Client-Secret sind sie nur schwer zu verwenden. Bewahren Sie Ihr Clientsecret geheim auf.

Einmalcode-Vorgang implementieren

Die Schaltfläche „Über Google anmelden“ stellt sowohl ein Zugriffstoken als auch einen Autorisierungscode bereit. Der Code ist ein Einmalcode, den Ihr Server gegen ein Zugriffstoken mit den Google-Servern austauschen kann.

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

Für die Authentifizierung der Google-Anmeldung mit dem Einmalcode-Vorgang müssen Sie Folgendes tun:

Schritt 1: Client-ID und Clientschlüssel erstellen

Wenn Sie eine Client-ID und ein Client-Secret erstellen möchten, erstellen Sie ein Google API Console-Projekt, richten Sie eine OAuth-Client-ID ein und registrieren Sie Ihre JavaScript-Quellen:

  1. Gehen Sie zur Google API Console.

  2. Wählen Sie im Drop-down-Menü „Projekt“ ein vorhandenes Projekt aus oder erstellen Sie ein neues, indem Sie Neues Projekt erstellen auswählen.

  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 drücken 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 Ursprünge, von denen aus Ihre App auf die Google APIs zugreifen darf, wie unten beschrieben. Eine Quelle ist eine eindeutige Kombination aus Protokoll, Hostnamen und Port.

    1. Geben Sie im Feld Autorisierte JavaScript-Quellen die Quelle für Ihre App ein. Sie können mehrere Quellen eingeben, damit Ihre App auf 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. Für das Feld Autorisierter Weiterleitungs-URI ist kein Wert erforderlich. Weiterleitungs-URIs werden nicht mit JavaScript APIs verwendet.

    3. Klicken Sie auf Erstellen.

  6. Kopieren Sie im angezeigten Dialogfeld OAuth-Client die Client-ID. Über die Client-ID kann Ihre App auf aktivierte Google APIs zugreifen.

Schritt 2: Google-Plattformbibliothek auf Ihrer Seite einfügen

Fügen Sie die folgenden Scripts ein, die eine anonyme Funktion zeigen, die ein Script 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

Lade die auth2-Bibliothek und rufe gapi.auth2.init() auf, um das GoogleAuth-Objekt zu initialisieren. Geben Sie beim Aufruf von init() Ihre Client-ID und die gewünschten Bereiche an.

<!-- 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 auf der 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 Ablauf für den 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 App Zugriff auf die von Ihnen 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 ein Einmalcode, den dein Server gegen ein eigenes Zugriffs- und Aktualisierungstoken eintauschen 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 du in Schritt 4 select-account prompt in OfflineAccessOptions angegeben hast, musst du das abgerufene Aktualisierungstoken für später speichern, da bei nachfolgenden Austauschen null für das Aktualisierungstoken zurückgegeben wird. Dieser Ablauf bietet mehr Sicherheit im Vergleich zum standardmäßigen OAuth 2.0-Vorgang.

Zugriffstokens werden immer beim Austausch eines gültigen Autorisierungscodes 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 ein Zugriffstoken austauschen

Tausche den Autorisierungscode auf dem Server gegen Zugriffs- und Aktualisierungstokens aus. Verwenden Sie das Zugriffstoken, um im Namen des Nutzers Google APIs aufzurufen, und speichern Sie optional das Aktualisierungstoken, um ein neues Zugriffstoken abzurufen, wenn das aktuelle abläuft.

Wenn Sie den Profilzugriff angefordert haben, erhalten Sie außerdem ein ID-Token mit grundlegenden Profilinformationen für den Nutzer.

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']