Logowanie przez Google w aplikacjach po stronie serwera

Aby korzystać z usług Google w imieniu użytkownika, gdy jest on offline, musisz użyć hybrydowego procesu po stronie serwera, w którym użytkownik autoryzuje aplikację po stronie klienta za pomocą klienta JavaScript API, a Ty wysyłasz do serwera specjalny jednorazowy kod autoryzacji. Serwer wymienia ten jednorazowy kod, aby uzyskać własny dostęp i tokeny odświeżania od Google, tak aby serwer mógł wykonywać własne wywołania interfejsu API, co jest możliwe, gdy użytkownik jest offline. Ten jednorazowy przepływ kodu ma dodatkowe zalety pod względem bezpieczeństwa zarówno w przypadku przepływu danych po stronie serwera, jak i wysyłania tokenów dostępu do serwera.

Poniżej przedstawiamy proces logowania się w celu uzyskania tokena dostępu do aplikacji po stronie serwera.

Kody jednorazowe mają kilka zalet pod względem bezpieczeństwa. Dzięki kodom Google udostępnia tokeny bezpośrednio na Twój serwer, bez udziału pośredników. Chociaż nie zalecamy ujawniania kodów, bardzo trudno jest z nich korzystać bez tajnego klucza klienta. Nie ujawniaj tajemnicy klienta.

Wdrażanie procesu z kodem jednorazowym

Przycisk logowania przez Google zawiera token dostępu i kod autoryzacji. Jest to jednorazowy kod, który Twój serwer może wymieniać z serwerami Google, aby uzyskać token dostępu.

Poniższy przykładowy kod pokazuje, jak wykonać przepływ jednorazowego kodu.

Uwierzytelnianie logowania Google za pomocą jednorazowego kodu wymaga:

Krok 1. Utwórz identyfikator klienta i tajny klucz klienta

Aby utworzyć identyfikator klienta i tajny klucz klienta, utwórz projekt w Konsoli interfejsów API Google, skonfiguruj identyfikator klienta OAuth i zarejestruj źródła JavaScript:

  1. Otwórz konsolę interfejsów API Google.

  2. Z menu projektu wybierz istniejący projekt lub utwórz nowy. W tym celu kliknij Utwórz nowy projekt.

  3. Na pasku bocznym w sekcji „Interfejsy API i usługi” wybierz Dane logowania i kliknij Skonfiguruj ekran zgody.

    Wybierz adres e-mail, podaj nazwę produktu i kliknij Zapisz.

  4. Na karcie Dane logowania kliknij listę Utwórz dane logowania i wybierz Identyfikator klienta OAuth.

  5. W sekcji Typ aplikacji wybierz Aplikacja internetowa.

    Zarejestruj źródła, z których aplikacja może uzyskiwać dostęp do interfejsów API Google, w ten sposób. Źródło to unikalna kombinacja protokołu, nazwy hosta i portu.

    1. W polu Autoryzowane źródła JavaScript wpisz źródło aplikacji. Możesz podać wiele źródeł, aby aplikacja mogła działać w różnych protokołach, domenach lub subdomenach. Nie można używać symboli wieloznacznych. W przykładzie poniżej drugi adres URL może być adresem produkcyjnym.

      http://localhost:8080
      https://myproductionurl.example.com
      
    2. Pole Identyfikator URI przekierowania autoryzowanego przekierowania nie wymaga wartości. Identyfikatory URI przekierowania nie są używane z interfejsami API JavaScript.

    3. Kliknij przycisk Utwórz.

  6. W wyświetlonym oknie Klient OAuth skopiuj identyfikator klienta. Identyfikator klienta umożliwia aplikacji dostęp do włączonych interfejsów API Google.

Krok 2. Umieść na stronie bibliotekę platformy Google

Dołącz skrypty poniżej przedstawiające anonimową funkcję, która wstawia skrypt w modelu DOM tej strony internetowej index.html.

<!-- 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 -->

Krok 3. Zainicjuj obiekt GoogleAuth

Wczytaj bibliotekę auth2 i wywołaj gapi.auth2.init(), aby zainicjować obiekt GoogleAuth. Podaj swój identyfikator klienta i zakresy, których chcesz żądać podczas wywoływania funkcji init().

<!-- 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>

Krok 4. Dodaj do swojej strony przycisk logowania

Dodaj do swojej strony internetowej przycisk logowania i dołącz moduł obsługi kliknięć, by wywołać metodę grantOfflineAccess(), co pozwoli na uruchomienie przepływu kodu jednorazowego.

<!-- 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>

Krok 5. Zaloguj się

Użytkownik klika przycisk logowania i przyznaje aplikacji dostęp do wymaganych uprawnień. Następnie funkcja wywołania zwrotnego określona w metodzie grantOfflineAccess().then() jest przekazywana do obiektu JSON z kodem autoryzacji. Na przykład:

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

Krok 6. Wyślij kod autoryzacji na serwer

code to Twój jednorazowy kod, który serwer może wymienić na własny token dostępu i token odświeżania. Token odświeżania możesz uzyskać dopiero po wyświetleniu użytkownikowi okna autoryzacji z prośbą o dostęp offline. Jeśli został określony select-account prompt w OfflineAccessOptions kroku 4, musisz zapisać pobrany token odświeżania do późniejszego użycia, ponieważ kolejne giełdy zwracają token odświeżania null. Ten proces zapewnia większe bezpieczeństwo w porównaniu ze standardowym przepływem OAuth 2.0.

Tokeny dostępu są zawsze zwracane po wymianie prawidłowego kodu autoryzacji.

Poniższy skrypt określa funkcję wywołania zwrotnego dla przycisku logowania. Gdy logowanie się uda, funkcja zapisuje token dostępu do użytku po stronie klienta i wysyła jednorazowy kod do Twojego serwera w tej samej domenie.

<!-- 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>

Krok 7. Wymień kod autoryzacji na token dostępu

Na serwerze wymień kod autoryzacji na tokeny dostępu i odświeżanie. Za pomocą tokena dostępu możesz wywoływać interfejsy API Google w imieniu użytkownika i opcjonalnie zapisać token odświeżania, aby uzyskać nowy token dostępu po jego wygaśnięciu.

Jeśli poprosisz o dostęp do profilu, otrzymasz też token identyfikatora zawierający podstawowe informacje o profilu użytkownika.

Na przykład:

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