Autenticar com um servidor de back-end

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

Enviar o token de ID para o servidor

Depois que um usuário fizer login, acesse o token de ID dele:

Swift

GIDSignIn.sharedInstance.signIn(withPresenting: self) { signInResult, error in
    guard error == nil else { return }
    guard let signInResult = signInResult else { return }

    signInResult.user.refreshTokensIfNeeded { user, error in
        guard error == nil else { return }
        guard let user = user else { return }

        let idToken = user.idToken
        // Send ID token to backend (example below).
    }
}

Objective-C

[GIDSignIn.sharedInstance signInWithPresentingViewController:self
                                              completion:^(GIDSignInResult * _Nullable signInResult,
                                                           NSError * _Nullable error) {
      if (error) { return; }
      if (signInResult == nil) { return; }

      [signInResult.user refreshTokensIfNeededWithCompletion:^(GIDGoogleUser * _Nullable user,
                                                               NSError * _Nullable error) {
          if (error) { return; }
          if (user == nil) { return; }

          NSString *idToken = user.idToken;
          // Send ID token to backend (example below).
      }];
}];

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

Swift

func tokenSignInExample(idToken: String) {
    guard let authData = try? JSONEncoder().encode(["idToken": idToken]) else {
        return
    }
    let url = URL(string: "https://yourbackend.example.com/tokensignin")!
    var request = URLRequest(url: url)
    request.httpMethod = "POST"
    request.setValue("application/json", forHTTPHeaderField: "Content-Type")

    let task = URLSession.shared.uploadTask(with: request, from: authData) { data, response, error in
        // Handle response from your backend.
    }
    task.resume()
}

Objective-C

NSString *signinEndpoint = @"https://yourbackend.example.com/tokensignin";
NSDictionary *params = @{@"idtoken": idToken};

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:signinEndpoint];
[request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
[request setHTTPMethod:@"POST"];
[request setHTTPBody:[self httpBodyForParamsDictionary:params]];

NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[NSURLConnection sendAsynchronousRequest:request
                                   queue:queue
                       completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
                         if (error) {
                           NSLog(@"Error: %@", error.localizedDescription);
                         } else {
                           NSLog(@"Signed in as %@", data.bytes);
                         }
                       }];

Verificar a integridade do token de ID

Depois de receber o token de ID por POST HTTPS, é necessário verificar 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 声明。

调用 tokeninfo 端点

调试验证 ID 令牌签名的一种简单方法是 使用 tokeninfo 端点。调用此端点涉及 这个额外的网络请求会为您完成大部分的验证工作, 验证和载荷提取。不适合在生产环境中使用 因为请求可能会受到限制或出现间歇性错误。

如需使用 tokeninfo 端点验证 ID 令牌,请创建 HTTPS POST 或 GET 请求发送到端点,并在 id_token 参数。 例如,要验证令牌“XYZ123”,请发出以下 GET 请求:

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

如果令牌经过正确签名,并且 issexp 具有预期值,就会收到 HTTP 200 响应,其中正文 包含 JSON 格式的 ID 令牌声明。 以下是示例响应:

{
 // 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"
}

如果您需要验证 ID 令牌是否代表 Google Workspace 账号,可以先查看 hd 声明,指示用户的托管网域。只有在以下情况下, 从而仅允许特定网域中的成员访问资源。缺少此声明 表示该账号不属于 Google Workspace 托管网域。

Criar uma conta ou sessão

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

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

Quando você usa o Google para fazer login de um usuário, você se beneficia automaticamente de todos os recursos de segurança e 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 no caso de haver um evento de segurança significativo, o app também poderá ficar vulnerável a ataques. Para proteger melhor suas contas contra eventos de segurança importantes, use a Proteção entre contas para receber alertas de segurança do Google. Quando receber esses eventos, ganhar visibilidade de alterações importantes na segurança da Conta do Google do usuário e você poderá tomar providências no serviço para proteger suas contas.