OpenID连接

Google的OpenID Connect端点已通过OpenID认证。

Google的OAuth 2.0 API可用于身份验证和授权。本文档介绍了我们的OAuth 2.0身份验证实现,该实现符合OpenID Connect规范,并且已通过OpenID认证使用OAuth 2.0访问Google API中的文档也适用于此服务。如果您想以交互方式探索此协议,建议您使用Google OAuth 2.0 Playground 。要获取有关Stack Overflow的帮助,请使用“ google-oauth”标记您的问题。

设置OAuth 2.0

在您的应用程序可以使用Google的OAuth 2.0身份验证系统进行用户登录之前,您必须在Google API Console中设置一个项目以获取OAuth 2.0凭据,设置重定向URI,并(可选)自定义用户在用户上看到的品牌信息-同意屏幕。您还可以使用API Console创建服务帐户,启用计费,设置过滤以及执行其他任务。有关更多详细信息,请参见Google API Console帮助

获取OAuth 2.0凭据

您需要OAuth 2.0凭据(包括客户端ID和客户端机密)来对用户进行身份验证并获得对Google API的访问权限。

要查看给定OAuth 2.0凭据的客户端ID和客户端密钥,请单击以下文本: 选择凭据 。在打开的窗口中,选择您的项目和所需的凭证,然后单击“ 查看”

或者,从API Console的“ 凭据”页面中查看您的客户端ID和客户端密钥:

  1. Go to the Credentials page.
  2. 单击您的凭证名称或铅笔( )图标。您的客户ID和密码位于页面顶部。

设置重定向URI

您在API Console中设置的重定向URI决定了Google将响应发送到身份验证请求的位置

要创建,查看或编辑给定OAuth 2.0凭据的重定向URI,请执行以下操作:

  1. Go to the Credentials page.
  2. 在页面的OAuth 2.0客户端ID部分中,点击一个凭据。
  3. 查看或编辑重定向URI。

如果“凭据”页面上没有OAuth 2.0客户端ID部分,则您的项目没有OAuth凭据。要创建一个,点击创建凭证

自定义用户同意屏幕

对于您的用户,OAuth 2.0身份验证体验包括一个同意屏幕,该屏幕描述了用户发布的信息以及适用的条款。例如,当用户登录时,可能会要求他们向您的应用授予访问其电子邮件地址和基本帐户信息的权限。您可以使用scope参数来请求访问此信息,该参数包含在您的应用程序的身份验证请求中。您还可以使用范围来请求访问其他Google API。

用户同意屏幕还显示品牌信息,例如您的产品名称,徽标和主页URL。您可以在API Console中控制品牌信息。

要启用项目的同意屏幕:

  1. Consent Screen page中打开Google API Console 。
  2. If prompted, select a project, or create a new one.
  3. 填写表格,然后点击保存

以下同意对话框显示了当请求中同时包含OAuth 2.0和Google Drive范围时,用户将看到的内容。 (此通用对话框是使用Google OAuth 2.0 Playground生成的,因此它不包含将在API Console中设置的品牌信息。)

同意页面屏幕截图

访问服务

Google和第三方提供了一些库,您可以使用它们来处理实现用户身份验证和访问Google API的许多实施细节。示例包括可用于各种平台的Google登录Google客户端库

如果选择不使用库,请遵循本文档其余部分中的说明,该说明描述了可用库下面的HTTP请求流。

验证用户

对用户进行身份验证涉及获取ID令牌并对其进行验证。 ID令牌OpenID Connect的标准化功能,旨在用于在Internet上共享身份声明。

用于验证用户身份和获取ID令牌的最常用方法称为“服务器”流和“隐式”流。服务器流允许应用程序的后端服务器使用浏览器或移动设备来验证人员的身份。当客户端应用程序(通常是在浏览器中运行的JavaScript应用程序)需要直接访问API而不是通过后端服务器访问API时,将使用隐式流程。

本文档介绍了如何执行用于验证用户身份的服务器流。由于在客户端上处理和使用令牌时存在安全风险,因此隐式流程要复杂得多。如果您需要实现隐式流程,我们强烈建议您使用Google登录

服务器流

确保在API Console中设置了应用程序,以使其能够使用这些协议并对用户进行身份验证。当用户尝试使用Google登录时,您需要:

  1. 创建一个防伪状态令牌
  2. 向Google发送身份验证请求
  3. 确认防伪状态令牌
  4. 交换访问令牌和ID令牌的code
  5. 从ID令牌获取用户信息
  6. 验证用户

1.创建一个防伪状态令牌

您必须通过防止请求伪造攻击来保护用户的安全。第一步是创建一个唯一的会话令牌,该令牌保存应用程序与用户客户端之间的状态。稍后,您将此唯一的会话令牌与Google OAuth登录服务返回的身份验证响应进行匹配,以验证用户是在发出请求,而不是恶意攻击者。这些令牌通常称为跨站点请求伪造( CSRF )令牌。

一个状态令牌的一个不错的选择是使用高质量随机数生成器构造的30个左右的字符的字符串。另一个是通过使用后端保密的密钥对某些会话状态变量进行签名而生成的哈希。

以下代码演示了如何生成唯一的会话令牌。

的PHP

您必须下载PHPGoogle API客户端库才能使用此示例。

// Create a state token to prevent request forgery.
// Store it in the session for later validation.
$state = bin2hex(random_bytes(128/8));
$app['session']->set('state', $state);
// Set the client ID, token state, and application name in the HTML while
// serving it.
return $app['twig']->render('index.html', array(
    'CLIENT_ID' => CLIENT_ID,
    'STATE' => $state,
    'APPLICATION_NAME' => APPLICATION_NAME
));

爪哇

您必须下载JavaGoogle API客户端库才能使用此示例。

// Create a state token to prevent request forgery.
// Store it in the session for later validation.
String state = new BigInteger(130, new SecureRandom()).toString(32);
request.session().attribute("state", state);
// Read index.html into memory, and set the client ID,
// token state, and application name in the HTML before serving it.
return new Scanner(new File("index.html"), "UTF-8")
    .useDelimiter("\\A").next()
    .replaceAll("[{]{2}\\s*CLIENT_ID\\s*[}]{2}", CLIENT_ID)
    .replaceAll("[{]{2}\\s*STATE\\s*[}]{2}", state)
    .replaceAll("[{]{2}\\s*APPLICATION_NAME\\s*[}]{2}",
    APPLICATION_NAME);

Python

您必须下载适用于PythonGoogle API客户端库才能使用此示例。

# Create a state token to prevent request forgery.
# Store it in the session for later validation.
state = hashlib.sha256(os.urandom(1024)).hexdigest()
session['state'] = state
# Set the client ID, token state, and application name in the HTML while
# serving it.
response = make_response(
    render_template('index.html',
                    CLIENT_ID=CLIENT_ID,
                    STATE=state,
                    APPLICATION_NAME=APPLICATION_NAME))

2.向Google发送身份验证请求

下一步是使用适当的URI参数形成HTTPS GET请求。请注意,在此过程的所有步骤中,均使用HTTPS而不是HTTP。 HTTP连接被拒绝。您应该使用authorization_endpoint元数据值从发现文档中检索基本URI。以下讨论假定基本URI为https://accounts.google.com/o/oauth2/v2/auth

对于基本请求,请指定以下参数:

  • 从API Console Credentials page获得的client_id
  • response_type ,它在基本授权码流请求中应该是code 。 (有关更多信息,请response_type 。)
  • scope ,在基本请求中应为openid email 。 (有关scope更多信息,请scope 。)
  • redirect_uri应该是您服务器上的HTTP端点,它将接收来自Google的响应。该值必须与您在API Console Credentials page中配置的OAuth 2.0客户端的授权重定向URI之一完全匹配。如果此值与授权的URI不匹配,则请求将失败,并显示redirect_uri_mismatch错误。
  • state应包含防伪唯一会话令牌的值,以及用户返回到您的应用程序时恢复上下文所需的任何其他信息,例如起始URL。 (在state阅读更多。)
  • nonce是您的应用程序生成的随机值,可在存在时启用重播保护。
  • login_hint可以是用户的电子邮件地址或sub字符串,等效于用户的Google ID。如果您未提供login_hint且用户当前已登录,则同意屏幕将包括一个批准请求,用于将用户的电子邮件地址释放到您的应用程序中。 (有关更多信息,请login_hint 。)
  • 使用hd参数可以为特定G Suite域的用户优化OpenID Connect流。 (阅读更多hd 。)

这是一个完整的OpenID Connect身份验证URI的示例,带有换行符和空格以提高可读性:

https://accounts.google.com/o/oauth2/v2/auth?
 response_type=code&
 client_id=424911365001.apps.googleusercontent.com&
 scope=openid%20email&
 redirect_uri=https%3A//oauth2.example.com/code&
 state=security_token%3D138r5719ru3e1%26url%3Dhttps%3A%2F%2Foauth2-login-demo.example.com%2FmyHome&
 login_hint=jsmith@example.com&
 nonce=0394852-3190485-2490358&
 hd=example.com

如果您的应用程序请求有关用户的任何新信息,或者如果您的应用程序请求他们先前未批准的帐户访问权限,则必须征得用户的同意。

3.确认防伪状态令牌

响应将发送到您在请求中指定的redirect_uri 。所有响应都在查询字符串中返回,如下所示:

https://oauth2.example.com/code?state=security_token%3D138r5719ru3e1%26url%3Dhttps%3A%2F%2Foa2cb.example.com%2FmyHome&code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7&scope=openid%20email%20https://www.googleapis.com/auth/userinfo.email

在服务器上,您必须确认从Google收到的state与您在步骤1中创建的会话令牌相匹配。这种往返验证有助于确保用户(而不是恶意脚本)发出请求。

以下代码演示了如何确认您在步骤1中创建的会话令牌:

的PHP

您必须下载PHPGoogle API客户端库才能使用此示例。

// Ensure that there is no request forgery going on, and that the user
// sending us this connect request is the user that was supposed to.
if ($request->get('state') != ($app['session']->get('state'))) {
  return new Response('Invalid state parameter', 401);
}

爪哇

您必须下载JavaGoogle API客户端库才能使用此示例。

// Ensure that there is no request forgery going on, and that the user
// sending us this connect request is the user that was supposed to.
if (!request.queryParams("state").equals(
    request.session().attribute("state"))) {
  response.status(401);
  return GSON.toJson("Invalid state parameter.");
}

Python

您必须下载适用于PythonGoogle API客户端库才能使用此示例。

# Ensure that the request is not a forgery and that the user sending
# this connect request is the expected user.
if request.args.get('state', '') != session['state']:
  response = make_response(json.dumps('Invalid state parameter.'), 401)
  response.headers['Content-Type'] = 'application/json'
  return response

4.交换访问令牌和ID令牌的code

响应包括code参数,服务器可以交换访问令牌和ID令牌的一次性授权代码。您的服务器通过发送HTTPS POST请求进行此交换。 POST请求将发送到令牌端点,您应该使用token_endpoint元数据值从发现文档中检索该令牌端点。以下讨论假定端点为https://oauth2.googleapis.com/token 。该请求必须在POST正文中包含以下参数:

领域
code初始请求返回的授权码。
client_id您从API Console Credentials page获得的客户端ID,如获得OAuth 2.0凭证中所述
client_secret您从API Console Credentials page获得的客户端密钥,如获得OAuth 2.0凭据中所述
redirect_uri设置重定向URI中所述,用于API Console Credentials page中指定的给定client_id的授权重定向URI
grant_type该字段必须包含OAuth 2.0规范中定义authorization_code值。

实际的请求可能类似于以下示例:

POST /token HTTP/1.1
Host: oauth2.googleapis.com
Content-Type: application/x-www-form-urlencoded

code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7&
client_id=your-client-id&
client_secret=your-client-secret&
redirect_uri=https%3A//oauth2.example.com/code&
grant_type=authorization_code

对此请求的成功响应在JSON数组中包含以下字段:

领域
access_token可以发送到Google API的令牌。
expires_in访问令牌的剩余生存时间(以秒为单位)。
id_token一个JWT ,其中包含Google进行数字签名的有关用户的身份信息。
scope access_token授予的访问范围以空格分隔,区分大小写的字符串列表表示。
token_type标识返回的令牌的类型。此时,此字段始终具有值Bearer
refresh_token (可选的)

仅当在身份验证请求中将access_type参数设置为offline ,此字段才存在。有关详细信息,请参见刷新令牌

5.从ID令牌获取用户信息

ID令牌是JWT (JSON Web令牌),即经过密码签名的Base64编码的JSON对象。通常,在使用ID令牌之前先对其进行验证非常重要,但是由于您是通过无中介HTTPS渠道与Google直接通信,并使用客户机密向Google进行身份验证,因此您可以确信该令牌确实来自Google,并且有效。如果您的服务器将ID令牌传递给应用程序的其他组件,则其他组件在使用令牌之前先对其进行验证非常重要。

由于大多数API库都将验证与解码base64url编码的值并解析其中的JSON的工作结合在一起,因此,当您访问ID令牌中的声明时,您可能最终还是要验证令牌。

ID令牌的有效载荷

ID令牌是一个JSON对象,其中包含一组名称/值对。这是一个示例,其格式旨在提高可读性:

{
  "iss": "https://accounts.google.com",
  "azp": "1234987819200.apps.googleusercontent.com",
  "aud": "1234987819200.apps.googleusercontent.com",
  "sub": "10769150350006150715113082367",
  "at_hash": "HK6E_P6Dh8Y93mRNtsDB1Q",
  "hd": "example.com",
  "email": "jsmith@example.com",
  "email_verified": "true",
  "iat": 1353601026,
  "exp": 1353604926,
  "nonce": "0394852-3190485-2490358"
}

Google ID令牌可能包含以下字段(称为Claims ):

宣称假如描述
aud总是此ID令牌的目标受众。它必须是您应用程序的OAuth 2.0客户端ID之一。
exp总是到期时间,此后不得接受ID令牌。以Unix时间(整数秒)表示。
iat总是发行ID令牌的时间。以Unix时间(整数秒)表示。
iss总是响应的发行者的发行者标识符。始终https://accounts.google.comaccounts.google.com获取Google ID令牌。
sub总是用户的标识符,在所有Google帐户中都是唯一的,并且从未重复使用。一个Google帐户可以在不同的时间点具有多个电子邮件地址,但是sub值永远不会改变。在应用程序中将sub用作用户的唯一标识符键。最大长度为255个区分大小写的ASCII字符。
at_hash访问令牌哈希。提供验证,以确保访问令牌已绑定到身份令牌。如果在服务器流中向ID令牌颁发了access_token值,则始终包含此声明。此声明可以用作防止跨站点请求伪造攻击的备用机制,但是,如果您按照步骤1步骤3进行操作,则不必验证访问令牌。
azp授权演示者的client_id 。仅当请求ID令牌的一方与ID令牌的受众不同时才需要此声明。对于混合应用程序,在Google上可能就是这种情况,其中Web应用程序和Android应用程序具有不同的OAuth 2.0 client_id但是共享相同的Google API项目。
email用户的电子邮件地址。该值可能不是该用户唯一的,因此不适合用作主键。仅当您的范围包括email范围值时才提供。
email_verified如果已验证用户的电子邮件地址,则为true;否则为true。否则为假。
family_name用户的姓或名。存在name声明时可能会提供。
given_name用户的给定名称或名字。存在name声明时可能会提供。
hd用户的托管G Suite域。仅在用户属于托管域时提供。
locale用户的语言环境,由BCP 47语言标记表示。存在name声明时可能会提供。
name用户的全名,以可显示的形式。可能在以下情况下提供:
  • 请求范围包括字符串“个人资料”
  • ID令牌是通过令牌刷新返回的

存在name声明时,您可以使用它们来更新应用程序的用户记录。请注意,此声明永远不能保证存在。

nonce您的应用在身份验证请求中提供的nonce的值。您应该通过确保仅提供一次来实施针对重放攻击的保护。
picture用户个人资料图片的URL。可能在以下情况下提供:
  • 请求范围包括字符串“个人资料”
  • ID令牌是通过令牌刷新返回的

存在picture声明时,您可以使用它们来更新应用程序的用户记录。请注意,此声明永远不能保证存在。

profile用户个人资料页面的URL。可能在以下情况下提供:
  • 请求范围包括字符串“个人资料”
  • ID令牌是通过令牌刷新返回的

如果存在profile声明,则可以使用它们来更新应用程序的用户记录。请注意,此声明永远不能保证存在。

6.验证用户

从ID令牌获取用户信息后,您应该查询应用程序的用户数据库。如果用户已经存在于您的数据库中,并且Google API响应满足所有登录要求,则应该为该用户启动应用程序会话。

如果用户不在用户数据库中,则应将用户重定向到新用户注册流程。您可能可以根据从Google收到的信息来自动注册用户,或者至少可以预先填写注册表格上需要的许多字段。除了ID令牌中的信息之外,您还可以在我们的用户个人资料端点上获取其他用户个人资料信息

进阶主题

以下各节更详细地介绍了Google OAuth 2.0 API。该信息适用于对身份验证和授权具有高级要求的开发人员。

访问其他Google API

使用OAuth 2.0进行身份验证的优点之一是,您的应用程序可以在对用户进行身份验证的同时获得代表用户使用其他Google API的权限(例如YouTube,Google云端硬盘,日历或通讯录)。为此,请将您需要的其他范围包括在发送给Google的身份验证请求中。例如,要将用户的年龄段添加到身份验证请求中,请传递openid email https://www.googleapis.com/auth/profile.agerange.read的范围参数。在同意屏幕上会适当提示用户。您从Google收到的访问令牌使您可以访问与您请求和授予的访问范围相关的所有API。

刷新令牌

在您的API访问请求中,您可以请求在code交换期间返回刷新令牌。当用户不在应用程序中时,刷新令牌可为您的应用程序提供对Google API的连续访问权限。要请求刷新令牌,请在身份验证请求中将access_type参数设置为offline

注意事项:

  • 确保安全且永久地存储刷新令牌,因为您只能在第一次执行代码交换流程时获得刷新令牌。
  • 发出刷新令牌的数量有限制:每个客户端/用户组合一个限制,所有客户端中每个用户一个限制。如果您的应用程序请求太多刷新令牌,则可能会遇到这些限制,在这种情况下,较早的刷新令牌将停止工作。

有关更多信息,请参见刷新访问令牌(离线访问)

您可以通过将prompt参数设置为在身份验证请求中表示consent ,来提示用户重新授权您的应用。当包含prompt=consent时,即使您先前将所有范围授予了您的Google API项目,每次您的应用请求访问范围的授权时,都会显示同意屏幕。因此,仅在必要时才包含prompt=consent

有关prompt参数的更多信息,请参阅身份验证URI参数表中的prompt

身份验证URI参数

下表提供了Google OAuth 2.0身份验证API接受的参数的更完整说明。

范围必需的描述
client_id (必需的)您从API Console Credentials page获得的客户端ID字符串,如获得OAuth 2.0凭证中所述
nonce (必需的)由您的应用生成的随机值,可启用重播保护。
response_type (必需的)如果值为code ,则启动基本授权代码流,要求对令牌端点进行POST以获取令牌。如果该值为token id_tokenid_token token ,则启动“ 隐式”流程,要求在重定向URI上使用JavaScript来从URI #fragment标识符检索令牌。
redirect_uri (必需的)确定将响应发送到的位置。此参数的值必须与您在API Console Credentials page中设置的授权重定向值之一完全匹配(包括HTTP或HTTPS方案,大小写和结尾的“ /”(如果有))。
scope (必需的)

scope参数必须以openid值开头,然后包括profile值, email值或两者。

如果存在profile范围值,则ID令牌可能(但不能保证)包括用户的默认profile声明。

如果存在email范围值,则ID令牌包括emailemail_verified声明。

除了这些特定于OpenID的作用域之外,您的作用域参数还可以包括其他作用域值。所有作用域值必须以空格分隔。例如,如果您希望按文件访问用户的Google云端硬盘,则范围参数可能是openid profile email https://www.googleapis.com/auth/drive.file

有关可用范围的信息,请参阅Google API的OAuth 2.0范围或您要使用的Google API的文档。

state (可选,但强烈建议)

在协议中往返的不透明字符串;也就是说,它在“基本”流中作为URI参数返回,在“隐式”流中作为URI #fragment标识符返回。

state对于关联请求和响应可能很有用。因为您可以猜测您的redirect_uri ,所以使用state值可以提高您对传入连接是应用程序发起的身份验证请求的结果的保证。如果您在该state变量中生成随机字符串或对某些客户端状态(例如cookie)的哈希进行编码,则可以验证响应以另外确保请求和响应源自同一浏览器。这提供了针对诸如跨站点请求伪造之类的攻击的保护。

access_type (可选的)允许的值是offlineonline 。效果记录在“脱机访问”中;如果正在请求访问令牌,则除非指定offline值,否则客户端不会收到刷新令牌。
display (可选的) ASCII字符串值,用于指定授权服务器如何显示认证和同意用户界面页面。以下值已指定并由Google服务器接受,但对其行为没有任何影响: pagepopuptouchwap
hd (可选的)

hd (托管域)参数可简化G Suite托管帐户的登录过程。通过包含G Suite用户的域(例如, mycollege.edu ),可以指示应该为该域中的帐户优化帐户选择UI。要针对一般的G Suite帐户(而不只是一个域)进行优化,请设置一个星号( * ): hd=*

不要依赖此UI优化来控制谁可以访问您的应用程序,因为可以修改客户端请求。确保验证返回的ID令牌hd声明值与您期望的值匹配(例如mycolledge.edu )。与request参数不同,ID令牌hd声明包含在Google的安全令牌中,因此可以信任该值。

include_granted_scopes (可选的)如果为该参数提供值true ,并且授权请求被批准,则该授权将包括先前授予该用户/应用程序组合其他范围的所有授权;请参阅增量授权

请注意,您无法使用已安装的应用程序流进行增量授权。

login_hint (可选的)当您的应用知道正在尝试认证的用户时,它可以将此参数作为提示提供给认证服务器。传递此提示会抑制帐户选择器,并预先填写登录表单上的电子邮件框,或者选择适当的会话(如果用户使用多次登录),这可以帮助您避免在您的应用中出现问题登录错误的用户帐户。该值可以是电子邮件地址,也可以是sub字符串,与用户的Google ID等效。
prompt (可选的)字符串值的空格分隔列表,用于指定授权服务器是否提示用户重新认证和同意。可能的值为:
  • none

    授权服务器不显示任何身份验证或用户同意屏幕;如果用户尚未通过身份验证,并且未针对请求的范围进行预配置的同意,则它将返回错误。您可以使用none检查现有的身份验证和/或同意。

  • consent

    授权服务器在将信息返回给客户端之前提示用户同意。

  • select_account

    授权服务器提示用户选择用户帐户。这允许在授权服务器上拥有多个帐户的用户从他们可能具有当前会话的多个帐户中进行选择。

如果未指定任何值,并且用户先前未授权访问,则将向用户显示一个同意屏幕。

验证ID令牌

您需要验证服务器上的所有ID令牌,除非您知道它们直接来自Google。例如,您的服务器必须将其从客户端应用收到的所有ID令牌验证为真实。

在以下常见情况下,您可能会向服务器发送ID令牌:

  • 发送带有需要验证的请求的ID令牌。 ID令牌告诉您发出请求的特定用户,以及为该客户端授予该ID令牌的客户端。

ID令牌很敏感,如果被拦截,可能会被滥用。您必须确保仅通过HTTPS且仅通过POST数据或在请求标头内传输这些令牌,以确保安全地处理这些令牌。如果将ID令牌存储在服务器上,则还必须安全地存储它们。

使ID令牌有用的一件事是,您可以在应用程序的不同组件之间传递它们。这些组件可以将ID令牌用作轻量级身份验证机制,以对应用程序和用户进行身份验证。但是,在您可以使用ID令牌中的信息或将其用作用户已通过身份验证的断言之前,您必须对其进行验证。

验证ID令牌需要几个步骤:

  1. 验证ID令牌已由发行者正确签名。 Google签发的令牌使用在发现文档jwks_uri元数据值中指定的URI处找到的证书之一进行签名。
  2. 验证ID令牌中的iss声明的值等于https://accounts.google.comaccounts.google.com
  3. 验证ID令牌中aud声明的值是否等于您应用的客户端ID。
  4. 验证ID令牌的到期时间( exp索赔)是否还没有过去。
  5. 如果您在请求中指定了hd参数值,请验证ID令牌是否具有与接受的G Suite托管域匹配的hd声明。

第2步到第5步仅涉及字符串和日期比较,这很简单,因此在此不再详细介绍。

第一步更加复杂,涉及密码签名检查。为了进行调试,您可以使用Google的tokeninfo端点与服务器或设备上实现的本地处理进行比较。假设您的ID令牌的值为XYZ123 。然后,您将取消引用URI https://oauth2.googleapis.com/tokeninfo?id_token= XYZ123 。如果令牌签名有效,则响应将是其解码的JSON对象形式的JWT有效负载。

tokeninfo端点对于调试很有用,但出于生产目的,请从密钥端点检索Google的公共密钥并在本地执行验证。您应该使用jwks_uri元数据值从“发现”文档中检索密钥URI。对调试端点的请求可能受到限制,否则可能会出现间歇性错误。

由于Google很少更改其公共密钥,因此您可以使用HTTP响应的cache指令对它们进行高速缓存,并且在大多数情况下,与使用tokeninfo端点相比,执行本地验证的效率要高得多。此验证需要检索和解析证书,并进行适当的加密调用以检查签名。幸运的是,可以使用多种语言调试良好的库来完成此任务(请参见jwt.io )。

获取用户资料信息

要获取有关用户的其他配置文件信息,您可以使用访问令牌(您的应用程序在身份验证流程中接收到的访问令牌)和OpenID Connect标准:

  1. 为了符合OpenID,您必须在身份验证请求中包括openid profile范围值。

    如果要包括用户的电子邮件地址,可以指定其他范围的email值。要同时指定profileemail ,可以在身份验证请求URI中包括以下参数:

    scope=openid%20profile%20email
  2. 将访问令牌添加到授权标头中,并向userinfo端点发出HTTPS GET请求,您应该使用userinfo_endpoint元数据值从“发现”文档中检索该请求。 userinfo响应包括有关用户的信息,如OpenID Connect Standard Claims所述,以及Discovery文档中claims_supported元数据值中所述。用户或其组织可能选择提供或保留某些字段,因此您可能无法获得授权访问范围的每个字段的信息。

发现文件

OpenID Connect协议要求使用多个端点来认证用户,并请求资源,包括令牌,用户信息和公共密钥。

为了简化实现并提高灵活性,OpenID Connect允许使用“发现文档”,这是在知名位置找到的JSON文档,其中包含键值对,这些键值对提供有关OpenID Connect提供程序配置的详细信息,包括授权的URI。 ,令牌,吊销,用户信息和公共密钥端点。 Google的OpenID Connect服务的“发现”文档可以从以下位置检索:

https://accounts.google.com/.well-known/openid-configuration

要使用Google的OpenID Connect服务,您应该将发现文档URI( https://accounts.google.com/.well-known/openid-configuration )硬编码到您的应用程序中。您的应用程序将获取文档,在响应中应用缓存规则,然后根据需要从文档中检索端点URI。例如,要对用户进行身份验证,您的代码将检索authorization_endpoint元数据值(在下面的示例中为https://accounts.google.com/o/oauth2/v2/auth ),作为发送到的身份验证请求的基本URI。谷歌。

这是此类文档的示例;字段名称是在OpenID Connect Discovery 1.0中指定的名称(有关其含义,请参阅该文档)。这些值纯粹是说明性的,并且可能会更改,尽管它们是从实际Google Discovery文档的最新版本中复制而来的:

{
  "issuer": "https://accounts.google.com",
  "authorization_endpoint": "https://accounts.google.com/o/oauth2/v2/auth",
  "device_authorization_endpoint": "https://oauth2.googleapis.com/device/code",
  "token_endpoint": "https://oauth2.googleapis.com/token",
  "userinfo_endpoint": "https://openidconnect.googleapis.com/v1/userinfo",
  "revocation_endpoint": "https://oauth2.googleapis.com/revoke",
  "jwks_uri": "https://www.googleapis.com/oauth2/v3/certs",
  "response_types_supported": [
    "code",
    "token",
    "id_token",
    "code token",
    "code id_token",
    "token id_token",
    "code token id_token",
    "none"
  ],
  "subject_types_supported": [
    "public"
  ],
  "id_token_signing_alg_values_supported": [
    "RS256"
  ],
  "scopes_supported": [
    "openid",
    "email",
    "profile"
  ],
  "token_endpoint_auth_methods_supported": [
    "client_secret_post",
    "client_secret_basic"
  ],
  "claims_supported": [
    "aud",
    "email",
    "email_verified",
    "exp",
    "family_name",
    "given_name",
    "iat",
    "iss",
    "locale",
    "name",
    "picture",
    "sub"
  ],
  "code_challenge_methods_supported": [
    "plain",
    "S256"
  ]
}

您可以通过缓存“发现”文档中的值来避免HTTP往返。使用标准的HTTP缓存标头,应予以遵守。

客户端库

以下客户端库通过与流行的框架集成,使OAuth 2.0的实现更加简单:

符合OpenID Connect

Google的OAuth 2.0身份验证系统支持OpenID Connect Core规范的 必需功能。任何旨在与OpenID Connect一起使用的客户端都应与此服务进行互操作( OpenID请求对象除外)。