Cuando se usan Google Identity Services o el flujo de código de autorización de OAuth 2.0, Google devuelve el token de ID con el método POST al extremo de redireccionamiento. De manera alternativa, el flujo implícito de OIDC usa una solicitud GET. Por lo tanto, tu aplicación es responsable de transmitir de forma segura estas credenciales recibidas a tu servidor.
Este es el flujo implícito. El token de ID se devuelve dentro del fragmento de URL, que el código JavaScript del cliente debe analizar. Tu aplicación es responsable de implementar sus propios mecanismos de validación para garantizar la autenticidad de la solicitud y evitar ataques como CSRF.
HTTP/1.1 302 Found Location: https://<REDIRECT_URI>#access_token=<ACCESS_TOKEN>&token_type=bearer&expires_in=<TIME_IN_SECONDS>&scope=<SCOPE>&state=<STATE_STRING>
El token de ID se devuelve como el campo credential. Cuando se prepara para enviar el token de ID al servidor, la biblioteca de GIS agrega automáticamente g_csrf_token a la cookie del encabezado y al cuerpo de la solicitud. Este es un ejemplo de solicitud POST:
POST /auth/token-verification HTTP/1.1 Host: example.com Content-Type: application/json;charset=UTF-8 Cookie: g_csrf_token=<CSRF_TOKEN> Origin: https://example.com Content-Length: <LENGTH_OF_JSON_BODY> { "credential": "<ID_TOKEN>", "g_csrf_token": "<CSRF_TOKEN>", "client_id": "<CLIENT_ID>" }
Validar el
g_csrf_tokenpara evitar ataques de falsificación de solicitudes entre sitios (CSRF):- Extrae el valor del token CSRF de la cookie
g_csrf_token. - Extrae el valor del token CSRF del cuerpo de la solicitud. La biblioteca de GIS incluye este token en el cuerpo de la solicitud POST como un parámetro, también llamado
g_csrf_token. - Compara los dos valores del token.
- Si ambos valores están presentes y coinciden por completo, se considera que la solicitud es legítima y se originó en tu dominio.
- Si los valores no están presentes o no coinciden, el servidor debe rechazar la solicitud.
Esta verificación garantiza que la solicitud se haya iniciado desde JavaScript que se ejecuta en tu propio dominio, ya que solo tu dominio puede acceder a la cookie
g_csrf_token.
- Extrae el valor del token CSRF de la cookie
Verifica el token de ID.
Para verificar que el token sea válido, asegúrate de que se cumplan los siguientes criterios:
- Google firma correctamente el token de ID. Usa las claves públicas de Google (disponibles en formato JWK o PEM) para verificar la firma del token. Estas claves rotan con regularidad. Examina el encabezado
Cache-Controlen la respuesta para determinar cuándo debes recuperarlas de nuevo. - El valor de
auden el token de ID es igual a uno de los IDs de cliente de tu app. Esta verificación es necesaria para evitar que los tokens de ID emitidos para una app maliciosa se usen para acceder a datos sobre el mismo usuario en el servidor de backend de tu app. - El valor de
issen el token de ID es igual aaccounts.google.comohttps://accounts.google.com. - No pasó el tiempo de vencimiento (
exp) del token de ID. - Si necesitas validar que el token de ID representa una cuenta de organización de Google Workspace o Cloud Identity, puedes verificar el reclamo
hd, que indica el dominio alojado del usuario. Se debe usar cuando se restringe el acceso a un recurso solo a los miembros de ciertos dominios. La ausencia de este reclamo indica que la cuenta no pertenece a un dominio alojado por Google.
Con los campos
email,email_verifiedyhd, puedes determinar si Google aloja una dirección de correo electrónico y es autoritativo para ella. En los casos en que Google es autoritativo, se sabe que el usuario es el propietario legítimo de la cuenta, por lo que puedes omitir la contraseña o cualquier otro método de desafío.Casos en los que Google es una fuente acreditada:
- Si
emailtiene el sufijo@gmail.com, se trata de una cuenta de Gmail. email_verifiedes verdadero yhdestá configurado, se trata de una cuenta de Google Workspace.
Los usuarios pueden registrarse para obtener Cuentas de Google sin usar Gmail ni Google Workspace. Cuando
emailno contiene un sufijo@gmail.comyhdestá ausente, Google no es autoritativo y se recomiendan métodos de contraseña o de otro tipo para verificar al usuario.email_verifiedtambién puede ser verdadero, ya que Google verificó inicialmente al usuario cuando se creó la Cuenta de Google. Sin embargo, es posible que la propiedad de la cuenta de correo electrónico de terceros haya cambiado desde entonces.En lugar de escribir tu propio código para realizar estos pasos de verificación, te recomendamos que uses una biblioteca cliente de las APIs de Google para tu plataforma o una biblioteca JWT de uso general. Para el desarrollo y la depuración, puedes llamar a nuestro extremo de validación
tokeninfo.使用 Google API 客户端库
使用某个 Google API 客户端库(例如 Java、 Node.js、 PHP、 Python) 是在生产环境中验证 Google ID 令牌的推荐方法。
<ph type="x-smartling-placeholder"></ph> <ph type="x-smartling-placeholder"> </ph> 。 <ph type="x-smartling-placeholder">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 WEB_CLIENT_ID of the app that accesses the backend: .setAudience(Collections.singletonList(WEB_CLIENT_ID)) // Or, if multiple clients access the backend: //.setAudience(Arrays.asList(WEB_CLIENT_ID_1, WEB_CLIENT_ID_2, WEB_CLIENT_ID_3)) .build(); // (Receive idTokenString by HTTPS POST) GoogleIdToken idToken = verifier.verify(idTokenString); if (idToken != null) { Payload payload = idToken.getPayload(); // Print user identifier. This ID is unique to each Google Account, making it suitable for // use as a primary key during account lookup. Email is not a good choice because it can be // changed by the user. 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> 。 <ph type="x-smartling-placeholder">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: WEB_CLIENT_ID, // Specify the WEB_CLIENT_ID of the app that accesses the backend // Or, if multiple clients access the backend: //[WEB_CLIENT_ID_1, WEB_CLIENT_ID_2, WEB_CLIENT_ID_3] }); const payload = ticket.getPayload(); // This ID is unique to each Google Account, making it suitable for use as a primary key // during account lookup. Email is not a good choice because it can be changed by the user. 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> 。 <ph type="x-smartling-placeholder">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' => $WEB_CLIENT_ID]); // Specify the WEB_CLIENT_ID of the app that accesses the backend $payload = $client->verifyIdToken($id_token); if ($payload) { // This ID is unique to each Google Account, making it suitable for use as a primary key // during account lookup. Email is not a good choice because it can be changed by the user. $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> 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 WEB_CLIENT_ID of the app that accesses the backend: idinfo = id_token.verify_oauth2_token(token, requests.Request(), WEB_CLIENT_ID) # Or, if multiple clients access the backend server: # idinfo = id_token.verify_oauth2_token(token, requests.Request()) # if idinfo['aud'] not in [WEB_CLIENT_ID_1, WEB_CLIENT_ID_2, WEB_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. # This ID is unique to each Google Account, making it suitable for use as a primary key # during account lookup. Email is not a good choice because it can be changed by the user. userid = idinfo['sub'] except ValueError: # Invalid token pass
verify_oauth2_token函数验证 JWT 签名、aud声明和exp声明。 您还必须验证hd检查verify_oauth2_token返回。如果多个客户端访问 后端服务器,另请手动验证aud声明。- Google firma correctamente el token de ID. Usa las claves públicas de Google (disponibles en formato JWK o PEM) para verificar la firma del token. Estas claves rotan con regularidad. Examina el encabezado
Una vez que se confirme la validez del token, puedes usar la información del token de ID de Google para correlacionar el estado de la cuenta de tu sitio:
Usuario no registrado: Puedes mostrar una interfaz de usuario (IU) de registro que permita al usuario proporcionar información de perfil adicional, si es necesario. También permite que el usuario cree de forma silenciosa la cuenta nueva y una sesión de usuario con acceso.
Una cuenta existente que ya existe en tu sitio: Puedes mostrar una página web que permita al usuario final ingresar su contraseña y vincular la cuenta heredada con sus credenciales de Google. Esto confirma que el usuario tiene acceso a la cuenta existente.
Un usuario federado que regresa: Puedes acceder de forma silenciosa.