Google Log-in für serverseitige Apps

Wenn Sie Google-Dienste im Namen eines Nutzers verwenden möchten, wenn der Nutzer offline ist, müssen Sie einen hybriden serverseitigen Ablauf verwenden, bei dem ein Nutzer Ihre Anwendung clientseitig mithilfe des JavaScript API-Clients autorisiert und Sie einen speziellen einmaligen Autorisierungscode an Ihren Server senden. Ihr Server tauscht diesen einmaligen Code aus, um seine eigenen Zugriffs- und Aktualisierungstokens von Google zu erhalten. Der Server kann dann eigene API-Aufrufe ausführen. Dies kann auch dann erfolgen, wenn der Nutzer offline ist. Dieser einmalige Codefluss bietet Sicherheitsvorteile gegenüber einem reinen serverseitigen Ablauf und gegenüber dem Senden von Zugriffstokens an Ihren Server.

Der Anmeldevorgang zum Abrufen eines Zugriffstokens für Ihre serverseitige Anwendung wird unten veranschaulicht.

Einmalige Codes bieten mehrere Sicherheitsvorteile. Bei Verwendung von Codes stellt Google Tokens ohne Zwischenhändler direkt auf Ihrem Server bereit. Obwohl wir nicht empfehlen, unlesbare Codes zu stehlen, sind sie ohne Ihren Clientschlüssel sehr schwer zu verwenden. Halten Sie Ihren Clientschlüssel geheim.

Ablauf mit einmaligem Code implementieren

Über die Schaltfläche „Google Log-in“ findest du sowohl ein Zugriffstoken als auch einen Autorisierungscode. Der Code ist ein einmaliger Code, den Ihr Server mit den Google-Servern gegen ein Zugriffstoken austauschen kann.

Der folgende Beispielcode zeigt, wie der einmalige Code-Vorgang durchgeführt wird.

Für die Authentifizierung von Google Log-in mit einem Einmalcode musst du Folgendes tun:

Schritt 1: Client-ID und Clientschlüssel erstellen

Um eine Client-ID und einen Clientschlüssel zu erstellen, musst du ein Google API Console-Projekt erstellen, eine OAuth-Client-ID einrichten und deine JavaScript-Quellen registrieren:

  1. Gehen Sie zur Google API Console.

  2. Wählen Sie in der Projekt-Drop-down-Liste 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 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, von denen Ihre App auf die Google APIs zugreifen darf: Ein Ursprung ist eine eindeutige Kombination aus Protokoll, Hostnamen und Port.

    1. Geben Sie im Feld Autorisierte JavaScript-Quellen den Ursprung für Ihre App ein. Sie können mehrere Ursprünge angeben, damit Ihre App mit 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. Im Feld Autorisierter Weiterleitungs-URI ist kein Wert erforderlich. Weiterleitungs-URIs werden nicht mit JavaScript APIs verwendet.

    3. Klicken Sie auf Erstellen.

  6. Kopieren Sie die Client-ID aus dem Dialogfeld OAuth-Client. Mit der Client-ID kann Ihre Anwendung auf aktivierte Google APIs zugreifen.

Schritt 2: Google-Plattformbibliothek in Ihre Seite einbinden

Fügen Sie die folgenden Skripts ein, die eine anonyme Funktion zeigen, mit der ein Skript in das DOM dieser index.html-Webseite eingefügt wird.

<!-- 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 GoogleAuth-Objekt zu initialisieren. Geben Sie beim Aufrufen von init() Ihre Client-ID und die Bereiche an, die Sie anfordern möchten.

<!-- 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 zur Seite hinzufügen

Fügen Sie der Webseite die Anmeldeschaltfläche hinzu und hängen Sie einen Klick-Handler an, mit dem grantOfflineAccess() aufgerufen wird, um den Vorgang mit einmaligem Code 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 angeforderten Berechtigungen. Anschließend wird an die 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 der Server gegen sein eigenes Zugriffstoken und Aktualisierungstoken austauschen kann. Sie können erst dann ein Aktualisierungstoken abrufen, wenn dem Nutzer ein Autorisierungsdialogfeld angezeigt wird, in dem der Offlinezugriff angefordert wird. Wenn Sie in Schritt 4 das select-account prompt in OfflineAccessOptions angegeben haben, müssen Sie das Aktualisierungstoken speichern, das Sie zur späteren Verwendung abrufen, da nachfolgende Austausche null für das Aktualisierungstoken zurückgeben. Dieser Ablauf bietet im Vergleich zum standardmäßigen OAuth 2.0-Vorgang mehr Sicherheit.

Zugriffstokens werden immer durch den Austausch eines gültigen Autorisierungscodes zurückgegeben.

Das folgende Skript definiert eine Callback-Funktion für die Anmeldeschaltfläche. Wenn eine Anmeldung erfolgreich ist, 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 auf dem Server den Autorisierungscode gegen Zugriffs- und Aktualisierungstoken aus. Verwenden Sie das Zugriffstoken, um Google APIs im Namen des Nutzers aufzurufen, und speichern Sie optional das Aktualisierungstoken, um nach Ablauf des Zugriffstokens ein neues Zugriffstoken zu erhalten.

Wenn Sie den Profilzugriff angefordert haben, erhalten Sie außerdem ein ID-Token, das grundlegende 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']