Autenticar com um servidor de back-end

Se você usa o Login do Google com um app ou site que se comunica com um servidor de back-end, talvez seja necessário identificar o usuário conectado no servidor. Para fazer isso com segurança, depois que um usuário fizer login, envie o token do ID do usuário para o servidor usando HTTPS. Em seguida, no servidor, verifique a integridade do token de ID e use as informações do usuário contidas nele para estabelecer uma sessão ou criar uma nova conta.

Enviar o token do ID para seu servidor

Primeiro, quando o usuário fizer login, solicite o token de ID:

  1. Ao configurar o Login do Google, chame o método requestIdToken e transmita o ID do cliente da Web do servidor para ele.

    // Request only the user's ID token, which can be used to identify the
    // user securely to your backend. This will contain the user's basic
    // profile (name, profile picture URL, etc) so you should not need to
    // make an additional call to personalize your application.
    GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
            .requestIdToken(getString(R.string.server_client_id))
            .requestEmail()
            .build();
  2. Quando seu app for iniciado, verifique se o usuário já fez login nele usando o Google, neste ou em outro dispositivo, chamando silentSignIn:

    GoogleSignIn.silentSignIn()
        .addOnCompleteListener(
            this,
            new OnCompleteListener<GoogleSignInAccount>() {
              @Override
              public void onComplete(@NonNull Task<GoogleSignInAccount> task) {
                handleSignInResult(task);
              }
            });
  3. Se o usuário não puder fazer login silenciosamente, apresente sua experiência normal sem login, oferecendo a opção de fazer login. Quando o usuário fizer login, acesse o GoogleSignInAccount dele no resultado da atividade da intent de login:

    // This task is always completed immediately, there is no need to attach an
    // asynchronous listener.
    Task<GoogleSignInAccount> task = GoogleSignIn.getSignedInAccountFromIntent(data);
    handleSignInResult(task);
  4. Depois que o usuário fizer login de forma silenciosa ou explícita, receba o token de ID do objeto GoogleSignInAccount:

    private void handleSignInResult(@NonNull Task<GoogleSignInAccount> completedTask) {
        try {
            GoogleSignInAccount account = completedTask.getResult(ApiException.class);
            String idToken = account.getIdToken();
    
            // TODO(developer): send ID Token to server and validate
    
            updateUI(account);
        } catch (ApiException e) {
            Log.w(TAG, "handleSignInResult:error", e);
            updateUI(null);
        }
    }

Em seguida, envie o token de ID para o seu servidor com uma solicitação HTTPS POST:

HttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost("https://yourbackend.example.com/tokensignin");

try {
  List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(1);
  nameValuePairs.add(new BasicNameValuePair("idToken", idToken));
  httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs));

  HttpResponse response = httpClient.execute(httpPost);
  int statusCode = response.getStatusLine().getStatusCode();
  final String responseBody = EntityUtils.toString(response.getEntity());
  Log.i(TAG, "Signed in as: " + responseBody);
} catch (ClientProtocolException e) {
  Log.e(TAG, "Error sending ID token to backend.", e);
} catch (IOException e) {
  Log.e(TAG, "Error sending ID token to backend.", e);
}

Verificar a integridade do token de ID

Depois de receber o token de ID por HTTPS POST, verifique a integridade do token.

Para verificar se o token é válido, verifique se: critérios sejam atendidos:

  • O token de ID está devidamente assinado pelo Google. Usar as chaves públicas do Google (disponível em JWK ou PEM) para verificar a assinatura do token. Essas chaves são trocadas regularmente. examinar o cabeçalho Cache-Control na resposta para determinar quando você deve recuperá-las novamente.
  • O valor de aud no token de ID é igual a um dos IDs de clientes. Essa verificação é necessária para evitar que os tokens de ID emitidos para um dispositivo app sendo usado para acessar dados sobre o mesmo usuário no servidor de back-end do seu app.
  • O valor de iss no token de ID é igual a accounts.google.com ou https://accounts.google.com.
  • O prazo de validade (exp) do token de ID não passou.
  • Se você precisar validar se o token de ID representa uma conta do Google Workspace ou da organização, verifique a declaração hd, que indica o servidor domínio do usuário. Isso deve ser usado ao restringir o acesso a um recurso apenas a membros da determinados domínios. A ausência dessa reivindicação indica que a conta não pertence a Domínio hospedado pelo Google.

Usando os campos email, email_verified e hd, é possível determinar se O Google hospeda e é autoritativo para um endereço de e-mail. Nos casos em que o Google é confiável, o usuário é conhecido como o proprietário legítimo da conta, e você pode ignorar a senha ou outras e métodos de desafio.

Casos em que o Google é confiável:

  • email tem o sufixo @gmail.com. Esta é uma conta do Gmail.
  • A opção email_verified é verdadeira e hd foi definida. Esta é uma conta do G Suite.

Os usuários podem se registrar para Contas do Google sem usar o Gmail ou o G Suite. Quando email não contém um sufixo @gmail.com e hd está ausente, o Google não está com autoridade e senha ou outros métodos de desafio o usuário. email_verified também pode ser verdadeiro porque o Google verificou inicialmente o usuário quando a Conta do Google foi criada, mas a propriedade do terceiro pode ter mudado desde então.

Em vez de escrever seu próprio código para executar essas etapas de verificação, é altamente recomendamos o uso de uma biblioteca de cliente de API do Google para sua plataforma ou uma biblioteca JWT. Para desenvolvimento e depuração, você pode chamar nossa classe tokeninfo endpoint de validação.

使用 Google API 客户端库

使用某个 Google API 客户端库(例如 JavaNode.jsPHPPython) 是在生产环境中验证 Google ID 令牌的推荐方法。

<ph type="x-smartling-placeholder">
</ph> <ph type="x-smartling-placeholder">
</ph>
Java

要在 Java 中验证 ID 令牌,请使用 GoogleIdTokenVerifier 对象。例如:

import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken.Payload;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier;

...

GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder(transport, jsonFactory)
    // Specify the CLIENT_ID of the app that accesses the backend:
    .setAudience(Collections.singletonList(CLIENT_ID))
    // Or, if multiple clients access the backend:
    //.setAudience(Arrays.asList(CLIENT_ID_1, CLIENT_ID_2, CLIENT_ID_3))
    .build();

// (Receive idTokenString by HTTPS POST)

GoogleIdToken idToken = verifier.verify(idTokenString);
if (idToken != null) {
  Payload payload = idToken.getPayload();

  // Print user identifier
  String userId = payload.getSubject();
  System.out.println("User ID: " + userId);

  // Get profile information from payload
  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");

  // Use or store profile information
  // ...

} else {
  System.out.println("Invalid ID token.");
}

GoogleIdTokenVerifier.verify() 方法验证 JWT 签名、aud 声明、iss 声明以及 exp 项版权主张。

如果您需要验证 ID 令牌是否代表 Google Workspace 或 Cloud 组织账号,您可以通过检查域名来验证 hd 所有权声明 由 Payload.getHostedDomain() 方法返回。该 email 声明不足以保证账号是由网域管理 或组织。

。 <ph type="x-smartling-placeholder">
</ph>
Node.js

要在 Node.js 中验证 ID 令牌,请使用适用于 Node.js 的 Google Auth 库。 安装该库:

npm install google-auth-library --save
然后,调用 verifyIdToken() 函数。例如:

const {OAuth2Client} = require('google-auth-library');
const client = new OAuth2Client();
async function verify() {
  const ticket = await client.verifyIdToken({
      idToken: token,
      audience: CLIENT_ID,  // Specify the CLIENT_ID of the app that accesses the backend
      // Or, if multiple clients access the backend:
      //[CLIENT_ID_1, CLIENT_ID_2, CLIENT_ID_3]
  });
  const payload = ticket.getPayload();
  const userid = payload['sub'];
  // If the request specified a Google Workspace domain:
  // const domain = payload['hd'];
}
verify().catch(console.error);

verifyIdToken 函数用于验证 JWT 签名、aud 声明、exp 声明 以及 iss 声明。

如果您需要验证 ID 令牌是否代表 Google Workspace 或 Cloud 组织账号时,您可以查看 hd 声明,该声明表示托管的 用户的网域。将资源访问权限限制为仅允许成员访问时,必须使用此设置 特定网域的用户缺少此声明即表示该账号不属于 Google 托管的域。

。 <ph type="x-smartling-placeholder">
</ph>
PHP

要在 PHP 中验证 ID 令牌,请使用适用于 PHP 的 Google API 客户端库。 安装该库(例如,使用 Composer):

composer require google/apiclient
然后,调用 verifyIdToken() 函数。例如:

require_once 'vendor/autoload.php';

// Get $id_token via HTTPS POST.

$client = new Google_Client(['client_id' => $CLIENT_ID]);  // Specify the CLIENT_ID of the app that accesses the backend
$payload = $client->verifyIdToken($id_token);
if ($payload) {
  $userid = $payload['sub'];
  // If the request specified a Google Workspace domain
  //$domain = $payload['hd'];
} else {
  // Invalid ID token
}

verifyIdToken 函数用于验证 JWT 签名、aud 声明、exp 声明 以及 iss 声明。

如果您需要验证 ID 令牌是否代表 Google Workspace 或 Cloud 组织账号时,您可以查看 hd 声明,该声明表示托管的 用户的网域。将资源访问权限限制为仅允许成员访问时,必须使用此设置 特定网域的用户缺少此声明即表示该账号不属于 Google 托管的域。

。 <ph type="x-smartling-placeholder">
</ph>
Python

要在 Python 中验证 ID 令牌,请使用 verify_oauth2_token 函数。例如:

from google.oauth2 import id_token
from google.auth.transport import requests

# (Receive token by HTTPS POST)
# ...

try:
    # Specify the CLIENT_ID of the app that accesses the backend:
    idinfo = id_token.verify_oauth2_token(token, requests.Request(), CLIENT_ID)

    # Or, if multiple clients access the backend server:
    # idinfo = id_token.verify_oauth2_token(token, requests.Request())
    # if idinfo['aud'] not in [CLIENT_ID_1, CLIENT_ID_2, CLIENT_ID_3]:
    #     raise ValueError('Could not verify audience.')

    # If the request specified a Google Workspace domain
    # if idinfo['hd'] != DOMAIN_NAME:
    #     raise ValueError('Wrong domain name.')

    # ID token is valid. Get the user's Google Account ID from the decoded token.
    userid = idinfo['sub']
except ValueError:
    # Invalid token
    pass

verify_oauth2_token 函数验证 JWT 签名、aud 声明和 exp 声明。 您还必须验证 hd 检查 verify_oauth2_token 返回。如果多个客户端访问 后端服务器,另请手动验证 aud 声明。

Como chamar o endpoint tokeninfo

Uma maneira fácil de validar uma assinatura de token de ID para depuração é use o endpoint tokeninfo. Chamar esse endpoint envolve uma solicitação de rede adicional que faz a maior parte da validação para você enquanto você testa as dependências validação e extração de payload no próprio código. Ele não é adequado para uso em produção já que as solicitações podem ser limitadas ou sujeitas a erros intermitentes.

Para validar um token de ID usando o endpoint tokeninfo, crie um solicitação POST ou GET para o ponto de extremidade e passe seu token de ID na parâmetro id_token. Por exemplo, para validar o token "XYZ123", faça a seguinte solicitação GET:

https://oauth2.googleapis.com/tokeninfo?id_token=XYZ123

Se o token estiver assinado corretamente e os iss e exp têm os valores esperados, você receberá uma resposta HTTP 200, em que o corpo contém as declarações do token de ID no formato JSON. Veja um exemplo de resposta:

{
 // These six fields are included in all Google ID Tokens.
 "iss": "https://accounts.google.com",
 "sub": "110169484474386276334",
 "azp": "1008719970978-hb24n2dstb40o45d4feuo2ukqmcc6381.apps.googleusercontent.com",
 "aud": "1008719970978-hb24n2dstb40o45d4feuo2ukqmcc6381.apps.googleusercontent.com",
 "iat": "1433978353",
 "exp": "1433981953",

 // These seven fields are only included when the user has granted the "profile" and
 // "email" OAuth scopes to the application.
 "email": "testuser@gmail.com",
 "email_verified": "true",
 "name" : "Test User",
 "picture": "https://lh4.googleusercontent.com/-kYgzyAWpZzJ/ABCDEFGHI/AAAJKLMNOP/tIXL9Ir44LE/s99-c/photo.jpg",
 "given_name": "Test",
 "family_name": "User",
 "locale": "en"
}

Se você precisar confirmar que o token de ID representa uma conta do Google Workspace, verifique a declaração hd, que indica o domínio hospedado do usuário. Deve ser usado quando restringir o acesso a um recurso apenas para membros de determinados domínios. A ausência desta declaração indica que a conta não pertence a um domínio hospedado do Google Workspace.

Criar uma conta ou sessão

Depois de verificar o token, verifique se o usuário já está no banco de dados de usuários. Se for o caso, estabeleça uma sessão autenticada para o usuário. Se o usuário ainda não estiver no banco de dados, crie um novo registro usando as informações no payload do token de ID e estabeleça uma sessão para o usuário. Você pode solicitar outras informações de perfil necessárias ao detectar um usuário recém-criado no app.

Como proteger as contas dos usuários com a Proteção entre contas

Ao confiar no Google para fazer o login de um usuário, você aproveita automaticamente todos os recursos de segurança e a infraestrutura que o Google criou para proteger os dados do usuário. No entanto, no caso improvável de a Conta do Google do usuário ser comprometida ou de alguma outra ocorrência de segurança significativa, seu app também poderá ficar vulnerável a ataques. Para proteger melhor suas contas contra grandes ocorrências de segurança, use a Proteção entre contas para receber alertas de segurança do Google. Ao receber esses eventos, você confere mudanças importantes na segurança da Conta do Google do usuário e pode tomar medidas no seu serviço para proteger suas contas.