Login do Google para apps do lado do servidor

Para usar os Serviços do Google em nome de um usuário quando ele estiver off-line, você vai precisar usar um fluxo híbrido do lado do servidor em que um usuário autoriza o app no cliente. usando o cliente da API JavaScript e enviar uma mensagem código de autorização para seu servidor. Seu servidor troca esse uso único para adquirir seus próprios tokens de acesso e atualização do Google para o servidor pode fazer as próprias chamadas de API, o que pode ser feito enquanto o usuário está off-line. Esse fluxo de código único tem vantagens de segurança em relação à interface pura e enviando tokens de acesso ao servidor.

Fluxo de login para receber um token de acesso para seu servidor está ilustrada abaixo.

Os códigos de uso único têm várias vantagens de segurança. Com os códigos, o Google fornece tokens diretamente ao seu servidor, sem nenhum intermediário. Embora não seja recomendado vazar códigos, eles são muito difíceis de usar sem a chave secreta do cliente. Mantenha o segredo do cliente em segredo.

Como implementar o fluxo de código único

O botão do Login do Google fornece um token de acesso e uma código de autorização. O código é único e pode ser trocado pelo servidor com os servidores do Google para receber um token de acesso.

O código de exemplo a seguir demonstra como fazer a fluxo de código único.

Para autenticar o Login do Google com o fluxo de código único, você precisa:

Etapa 1: criar um ID e uma chave secreta do cliente

Para criar um ID e uma chave secreta do cliente, crie um projeto no Console de APIs do Google. configure um ID do cliente OAuth e registre suas origens do JavaScript:

  1. Vá para o Console de APIs do Google.

  2. No menu suspenso do projeto, selecione um projeto existente ou crie um novo Selecione Criar um novo projeto.

  3. Na barra lateral, em "APIs e Serviços", selecione Credenciais e clique em Configurar a tela de consentimento.

    Escolha um endereço de e-mail, especifique um nome de produto e clique em Salvar.

  4. Na guia Credenciais, selecione o menu suspenso Criar credenciais. e escolha ID do cliente OAuth.

  5. Em Tipo de aplicativo, selecione Aplicativo da Web.

    Registre as origens das quais seu app tem permissão para acessar o APIs do Google, da seguinte maneira: Uma origem é uma combinação única de protocolos, nome do host e porta.

    1. No campo Origens JavaScript autorizadas, digite a origem do seu app. Você pode inserir várias origens para permitir a execução do seu app protocolos, domínios ou subdomínios diferentes. Não é possível usar caracteres curinga. No exemplo abaixo, o segundo URL poderia ser um URL de produção.

      http://localhost:8080
      https://myproductionurl.example.com
      
    2. O campo URI de redirecionamento autorizado não requer um valor. Redirecionamento Os URIs não são usados com APIs JavaScript.

    3. Pressione o botão Criar.

  6. Na caixa de diálogo Cliente OAuth, copie o ID do cliente. A Com o ID do cliente, seu app pode acessar as APIs ativadas do Google.

Etapa 2: incluir a biblioteca da Plataforma Google na sua página

Inclua os scripts a seguir que demonstram uma função anônima que insere um script no DOM desta página da Web do 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 -->

Etapa 3: inicializar o objeto GoogleAuth

Carregue a biblioteca auth2 e chame gapi.auth2.init() para inicializar o objeto GoogleAuth. Especifique seu ID do cliente e os escopos que você quer solicitar quando você chamar 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>

Etapa 4: adicionar o botão de login à sua página

Adicione o botão de login a sua página da Web e anexe um manipulador de cliques para chamar grantOfflineAccess() para iniciar o fluxo de código único.

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

Etapa 5: fazer o login do usuário

O usuário clica no botão de login e concede ao app acesso às permissões que você solicitou. Em seguida, a função de retorno de chamada especificada no grantOfflineAccess().then() recebe um objeto JSON com um código de autorização. Exemplo:

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

Etapa 6: enviar o código de autorização ao servidor

O code é um código único que seu servidor pode trocar pelo próprio token de acesso e de atualização. Só é possível obter um token de atualização após o usuário recebeu uma caixa de diálogo de autorização solicitando acesso off-line. Se você especificou o select-account prompt no OfflineAccessOptions na etapa 4, é necessário armazenar o token de atualização recuperado para uso posterior porque as trocas seguintes vão retornar null para o token de atualização. Este fluxo fornece mais segurança em relação ao fluxo padrão do OAuth 2.0.

Os tokens de acesso são sempre retornados com a troca de uma autorização válida o código-fonte.

O script a seguir define uma função de callback para o botão de login. Quando um login for bem-sucedido, a função armazena o token de acesso para acesso do lado do cliente use e envie o código de uso único para seu servidor no mesmo domínio.

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

Etapa 7: trocar o código de autorização por um token de acesso

No servidor, troque o código de autorização por tokens de acesso e de atualização. Use o token de acesso para chamar as APIs do Google em nome do usuário e, opcionalmente, armazenar o token de atualização para adquirir um novo token de acesso quando o token de acesso expirar.

Se você solicitou acesso ao perfil, também recebe um token de ID com informações de perfil para o usuário.

Exemplo:

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