OAuth로 Google 계정 연결

계정은 업계 표준 OAuth 2.0 암시적 흐름 및 승인 코드 흐름을 사용하여 연결됩니다. 서비스가 OAuth 2.0을 준수하는 승인토큰 교환 엔드포인트를 지원해야 합니다.

隐式流程中,Google 会在用户的浏览器中打开您的授权端点。成功登录后,您将向 Google 返回一个长期访问令牌。现在,此访问令牌会包含在 Google 发送的每个请求中。

授权代码流程中,您需要两个端点:

  • 授权端点,用于向尚未登录的用户显示登录界面。授权端点还会创建一个短期授权代码,以记录用户对所请求访问权限的同意情况。

  • 令牌交换端点,负责两种类型的交换:

    1. 使用授权代码换取长期有效的刷新令牌和短期有效的访问令牌。当用户完成账号关联流程时,就会发生此交换。
    2. 将长期有效的刷新令牌换成短期有效的访问令牌。当 Google 需要新的访问令牌(因为现有访问令牌已过期)时,就会发生这种交换。

选择 OAuth 2.0 流程

虽然隐式流程更易于实现,但 Google 建议通过隐式流程签发的访问令牌永不过期。这是因为,在隐式流程中,令牌过期后,系统会强制用户重新关联其账号。如果您出于安全考虑需要令牌过期,我们强烈建议您改用授权码流程。

设计准则

本部分介绍了您为 OAuth 关联流程托管的用户屏幕的设计要求和建议。在 Google 应用调用该 API 后,您的平台会向用户显示登录 Google 页面和账号关联意见征求界面。同意关联账号后,系统会将用户重定向回 Google 的应用。

此图展示了用户将其 Google 账号与您的身份验证系统相关联的步骤。第一个屏幕截图显示了用户从您的平台发起的关联。第二张图片显示用户登录 Google,第三张图片显示用户同意并确认将其 Google 账号与您的应用相关联。最后一张屏幕截图显示 Google 应用中成功关联的用户账号。
图 1.账号关联用户登录 Google 和同意屏幕。

要求

  1. 您必须说明用户的账号将与 Google 相关联,而非 Google Home 或 Google 助理等特定 Google 产品相关联。

建议

建议您执行以下操作:

  1. 显示 Google 的隐私权政策。在同意屏幕上添加指向 Google 隐私权政策的链接。

  2. 要共享的数据。使用清晰简洁的语言告知用户 Google 需要哪些用户数据以及原因。

  3. 添加醒目的号召性用语。在用户同意页面上提供明确的号召性用语,例如“同意并关联”。这是因为用户需要了解他们需要与 Google 分享哪些数据才能关联账号。

  4. 可以取消。为用户提供返回或取消链接的途径,如果用户选择不进行关联。

  5. 明确的登录流程。确保用户有明确的 Google 账号登录方法,例如用户名和密码字段或使用 Google 账号登录

  6. 能够解除关联。提供一种可让用户解除关联的机制,例如指向您平台上账号设置的网址。或者,您也可以添加指向 Google 账号的链接,以便用户管理其关联的账号。

  7. 能够更改用户账号。建议用户切换账号的方法。如果用户通常拥有多个账号,这种做法尤为有益。

    • 如果用户必须关闭意见征求界面才能切换账号,请向 Google 发送可恢复的错误,以便用户可以使用 OAuth 关联隐式流程登录所需的账号。
  8. 添加您的徽标。在意见征求页面上显示您的公司徽标。 按照您的样式准则放置徽标。如果您还想显示 Google 的徽标,请参阅徽标和商标

创建项目

如需创建使用账号关联的项目,请执行以下操作:

  1. 点击 Create project
  2. 输入名称或接受生成的建议。
  3. 确认或修改所有剩余字段。
  4. 点击创建

如需查看项目 ID,请执行以下操作:

  1. 在着陆页的表格中找到您的项目。项目 ID 会显示在 ID 列中。

Google 账号关联流程包含一个权限请求页面,该页面会告知用户哪个应用在请求访问其数据、请求访问哪些类型的数据,以及适用的条款。您需要先配置 OAuth 权限请求页面,然后才能生成 Google API 客户端 ID。

  1. 打开 Google API 控制台的 OAuth 同意屏幕页面。
  2. 如果出现提示,请选择您刚刚创建的项目。
  3. 在“OAuth 同意屏幕”页面上,填写表单,然后点击“保存”按钮。

    应用名称:征求用户同意的应用的名称。名称应准确反映您的应用,并与用户在其他位置看到的应用名称保持一致。应用名称将显示在账号关联权限请求界面上。

    应用徽标:权限请求页面上显示的一张图片,用以让用户认出您的应用。徽标会显示在账号关联权限请求页面和账号设置

    支持电子邮件地址:供用户就其同意问题与您联系。

    Google API 的范围:借助范围,您的应用可以访问用户的非公开 Google 数据。对于 Google 账号关联使用情形,默认范围(电子邮件地址、个人资料、openid)就足够了,您无需添加任何敏感范围。一般来说,最佳做法是在需要访问权限时逐步请求权限范围,而不是提前请求。了解详情

    已获授权的网域:为了保护您和您的用户,Google 只允许使用 OAuth 进行身份验证的应用使用已获授权的网域。应用的链接必须托管在已获授权的网域上。了解详情

    应用首页链接:应用的首页。必须托管在已获授权的网域上。

    应用隐私权政策链接:显示在 Google 账号关联意见征求界面上。必须托管在已获授权的网域上。

    应用服务条款链接(可选):必须托管在已获授权的网域上。

    图 1. 虚构应用 Tunery 的 Google 账号关联意见征求界面

  4. 查看“验证状态”,如果您的应用需要验证,请点击“提交以供验证”按钮,提交应用以供验证。如需了解详情,请参阅 OAuth 验证要求

OAuth 서버 구현

승인 코드 흐름의 OAuth 2.0 서버 구현은 다음으로 구성됩니다. 서비스가 HTTPS를 통해 사용할 수 있도록 하는 두 개의 엔드포인트 첫 번째 엔드포인트는 승인 엔드포인트로, 승인 엔드포인트는 사용자의 동의를 얻어야 합니다. 승인 엔드포인트는 로그인 UI를 사용자에게 제공하고 이에 대한 동의를 기록 액세스 권한을 요청합니다. 두 번째 엔드포인트는 토큰 교환 엔드포인트로, 토큰이라는 암호화된 문자열을 가져오는 데 사용되며, 이 문자열은 사용자에게 서비스에 액세스할 수 있습니다

Google 애플리케이션이 서비스의 API 중 하나를 호출해야 하는 경우 Google은 이러한 API를 호출할 수 있는 권한을 사용자로부터 얻기 위해 이러한 엔드포인트를 함께 모읍니다. 위임할 수 있습니다

Google에서 시작한 OAuth 2.0 승인 코드 흐름 세션에는 다음 흐름을 따라 하세요.

  1. Google은 사용자의 브라우저에서 승인 엔드포인트를 엽니다. 흐름이 작업을 위해 음성 전용 기기에서 시작된 경우 Google은 실행되는 것입니다.
  2. 사용자가 아직 로그인하지 않은 경우 로그인하여 Google에 다음 권한을 부여합니다. 아직 권한을 부여하지 않은 경우 API를 통해 데이터에 액세스할 수 있습니다.
  3. 서비스에서 승인 코드를 생성하여 Google에 반환합니다. 해야 할 일 승인 코드를 사용하여 사용자의 브라우저를 Google로 다시 리디렉션합니다. 이 요청에 첨부됩니다.
  4. Google은 토큰 교환 엔드포인트로 승인 코드를 전송합니다. 코드의 신뢰성을 확인하고 액세스 토큰갱신 토큰을 선택합니다. 액세스 토큰은 사용자 인증 정보로 수락합니다. 갱신 토큰은 새 액세스 토큰을 획득할 때 Google이 저장하고 사용할 수 있는 만료됩니다.
  5. 사용자가 계정 연결 흐름을 완료한 후 Google에서 전송한 요청에는 액세스 토큰이 포함됩니다.

승인 요청 처리

OAuth 2.0 승인 코드를 사용하여 계정 연결을 수행해야 하는 경우 Google은 승인 엔드포인트로 에는 다음 매개변수가 포함됩니다.

승인 엔드포인트 매개변수
client_id Google에 할당한 클라이언트 ID입니다.
redirect_uri 이 요청에 대한 응답을 보낼 URL입니다.
state 정해진 기간에 변경되지 않고 Google에 다시 전달되는 리디렉션 URI를 사용할 수 있습니다.
scope 선택사항: 공백으로 구분된 범위 문자열 집합으로, Google이 승인을 요청하는 데이터입니다.
response_type 응답에서 반환할 값의 유형입니다. OAuth 2.0의 경우 승인 코드 흐름에서 응답 유형은 항상 code입니다.
user_locale Google 계정 언어 설정 RFC5646 형식으로, 사용자가 선호하는 언어로 콘텐츠를 현지화하는 데 사용됩니다.

예를 들어 승인 엔드포인트를 https://myservice.example.com/auth인 경우 요청은 다음과 같을 수 있습니다.

GET https://myservice.example.com/auth?client_id=GOOGLE_CLIENT_ID&redirect_uri=REDIRECT_URI&state=STATE_STRING&scope=REQUESTED_SCOPES&response_type=code&user_locale=LOCALE

승인 엔드포인트가 로그인 요청을 처리하도록 하려면 다음을 수행합니다. 단계:

  1. client_id이 Google에 할당한 클라이언트 ID와 일치하고 redirect_uri가 Google에서 서비스에 제공한 리디렉션 URL과 일치하는지 확인합니다. 이러한 확인은 서비스 계정에 의도하지 않거나 잘못 구성된 클라이언트 앱에 액세스할 수 없습니다. 여러 개의 OAuth 2.0 흐름에서 response_typecode인지도 확인합니다.
  2. 사용자가 서비스에 로그인했는지 확인합니다. 사용자가 로그인하지 않은 경우 서비스의 로그인 또는 가입 흐름을 완료할 수 있습니다.
  3. Google에서 API에 액세스하는 데 사용할 승인 코드를 생성합니다. 승인 코드는 임의의 문자열 값이 될 수 있지만 고유해야 합니다. 사용자, 토큰의 대상 클라이언트, 코드의 만료 시간을 나타내는 추측할 수 없어야 합니다. 일반적으로 승인을 발행합니다. 코드는 약 10분 후에 만료됩니다.
  4. redirect_uri 매개변수로 지정된 URL에 다음 양식을 제출해 주세요.
      https://oauth-redirect.googleusercontent.com/r/YOUR_PROJECT_ID
      https://oauth-redirect-sandbox.googleusercontent.com/r/YOUR_PROJECT_ID
      
  5. 사용자의 브라우저를 redirect_uri 매개변수 제출한 승인 코드 포함 리디렉션할 때 수정되지 않은 원래 상태 값과 codestate 매개변수를 추가합니다. 다음은 결과 URL의 예는 다음과 같습니다.
    https://oauth-redirect.googleusercontent.com/r/YOUR_PROJECT_ID?code=AUTHORIZATION_CODE&state=STATE_STRING

토큰 교환 요청 처리

서비스의 토큰 교환 엔드포인트는 두 가지 종류의 토큰을 담당합니다. 있습니다.

  • 승인 코드를 액세스 토큰 및 갱신 토큰으로 교환
  • 갱신 토큰을 액세스 토큰으로 교환

토큰 교환 요청에는 다음 매개변수가 포함됩니다.

토큰 교환 엔드포인트 매개변수
client_id 요청 출처를 Google로 식별하는 문자열입니다. 이 문자열은 시스템 내에 Google의 고유 식별자로 등록되어 있어야 합니다.
client_secret 서비스를 위해 Google에 등록한 비밀번호 문자열입니다.
grant_type 교환되는 토큰의 유형입니다. 다음 중 하나에 해당합니다. authorization_code 또는 refresh_token
code grant_type=authorization_code인 경우 이 매개변수는 Google이 로그인 또는 토큰 교환에서 수신한 코드 할 수 있습니다
redirect_uri grant_type=authorization_code인 경우 이 매개변수는 초기 승인 요청에 사용된 URL입니다.
refresh_token grant_type=refresh_token인 경우 이 매개변수는 Google이 토큰 교환 엔드포인트에서 수신한 갱신 토큰입니다.
승인 코드를 액세스 토큰 및 갱신 토큰으로 교환

사용자가 로그인하고 승인 엔드포인트에서 단기 응답을 반환한 후 Google에서 토큰 교환으로 요청을 엔드포인트에서 승인 코드를 액세스 토큰으로 교환하고 토큰입니다.

이러한 요청에서 grant_type 값은 authorization_code이고 code 값은 이전에 부여한 승인 코드의 값입니다. Google에 문의하기 다음은 승인 코드는 다음과 같습니다.

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

client_id=GOOGLE_CLIENT_ID&client_secret=GOOGLE_CLIENT_SECRET&grant_type=authorization_code&code=AUTHORIZATION_CODE&redirect_uri=REDIRECT_URI

승인 코드를 액세스 토큰 및 갱신 토큰으로 교환하려면 토큰 교환 엔드포인트는 다음을 실행하여 POST 요청에 응답합니다. 단계:

  1. client_id이 요청 출처를 승인된 출처이고 client_secret가 예상값과 일치하는지 확인합니다.
  2. 승인 코드가 유효하고 만료되지 않았는지, 요청에 지정된 클라이언트 ID가 승인 코드가 필요합니다.
  3. redirect_uri 매개변수로 지정된 URL이 동일한지 확인 초기 승인 요청에 사용된 값으로 설정합니다.
  4. 위의 기준을 모두 확인할 수 없는 경우 {"error": "invalid_grant"}이 본문으로 있는 400 잘못된 요청 오류입니다.
  5. 그렇지 않은 경우 승인 코드의 사용자 ID를 사용하여 새로고침을 생성하세요. 액세스 토큰을 만들 수 있습니다 토큰은 임의의 문자열 값이 될 수 있지만 토큰이 대상으로 하는 사용자와 클라이언트를 고유하게 나타내야 하며, 추측할 수 없어야 합니다. 액세스 토큰의 경우 이 시간은 일반적으로 토큰을 발급하고 한 시간 후에 이뤄집니다 갱신 토큰은 만료되지 않습니다.
  6. HTTPS 응답 본문에 다음 JSON 객체를 반환합니다.
    {
    "token_type": "Bearer",
    "access_token": "ACCESS_TOKEN",
    "refresh_token": "REFRESH_TOKEN",
    "expires_in": SECONDS_TO_EXPIRATION
    }

Google에서 사용자 및 기록의 액세스 토큰과 갱신 토큰을 저장함 만료되어야 합니다 액세스 토큰이 만료되면 Google은 토큰 교환 엔드포인트에서 새 액세스 토큰을 가져옵니다.

갱신 토큰을 액세스 토큰으로 교환

액세스 토큰이 만료되면 Google에서 토큰 교환으로 요청을 전송합니다. 새 액세스 토큰으로 교환합니다.

이러한 요청에서 grant_type 값은 refresh_token이고 refresh_token는 이전에 부여한 갱신 토큰의 값입니다. Google 다음은 갱신 토큰 교환 요청의 예시입니다. 다음을 수행합니다.

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

client_id=GOOGLE_CLIENT_ID&client_secret=GOOGLE_CLIENT_SECRET&grant_type=refresh_token&refresh_token=REFRESH_TOKEN

갱신 토큰을 액세스 토큰으로 교환하려면 토큰 교환 엔드포인트 다음 단계를 실행하여 POST 요청에 응답합니다.

  1. client_id가 요청 출처를 Google로 식별하는지 확인합니다. client_secret가 예상값과 일치하는지 확인합니다.
  2. 갱신 토큰이 유효하고 요청이 갱신 토큰과 연결된 클라이언트 ID와 일치하는지 확인합니다.
  3. 위의 기준을 모두 확인할 수 없는 경우 HTTP 400을 반환합니다. 본문이 {"error": "invalid_grant"}인 잘못된 요청 오류입니다.
  4. 그렇지 않은 경우 갱신 토큰의 사용자 ID를 사용하여 액세스 권한을 생성하세요. 토큰입니다. 토큰은 임의의 문자열 값이 될 수 있지만 고유하게 사용자와 클라이언트를 나타내야 하며 있습니다. 액세스 토큰의 경우 토큰의 만료 시간도 기록합니다. 일반적으로 토큰을 발급하고 1시간 후에
  5. HTTPS의 본문에서 다음 JSON 객체를 반환합니다. 응답:
    {
    "token_type": "Bearer",
    "access_token": "ACCESS_TOKEN",
    "expires_in": SECONDS_TO_EXPIRATION
    }
를 통해 개인정보처리방침을 정의할 수 있습니다.
处理 userinfo 请求

userinfo 端点是受 OAuth 2.0 保护的资源,会返回关联用户的声明。实现和托管 userinfo 端点是可选的,但以下用例除外:

从您的令牌端点成功检索到访问令牌后,Google 会向您的 userinfo 端点发送请求,以检索关联用户的基本个人资料信息。

userinfo 端点请求标头
Authorization header Bearer 类型的访问令牌。

例如,如果您的 userinfo 端点可通过 https://myservice.example.com/userinfo 时,请求可能如下所示:

GET /userinfo HTTP/1.1
Host: myservice.example.com
Authorization: Bearer ACCESS_TOKEN

为了让 userinfo 端点能够处理请求,请执行以下步骤:

  1. 从 Authorization 标头中提取访问令牌,并返回与访问令牌相关联的用户的信息。
  2. 如果访问令牌无效,则使用 WWW-Authenticate 响应标头返回 HTTP 401 Unauthorized 错误。下面是一个 userinfo 错误响应示例:
    HTTP/1.1 401 Unauthorized
    WWW-Authenticate: error="invalid_token",
    error_description="The Access Token expired"
    
    如果在关联过程中返回 401 未经授权错误或任何其他失败的错误响应,该错误将无法恢复,检索到的令牌将被舍弃,并且用户必须重新开始关联流程。
  3. 如果访问令牌有效,则返回 HTTPS 正文中包含以下 JSON 对象的 HTTP 200 响应 回答:

    {
    "sub": "USER_UUID",
    "email": "EMAIL_ADDRESS",
    "given_name": "FIRST_NAME",
    "family_name": "LAST_NAME",
    "name": "FULL_NAME",
    "picture": "PROFILE_PICTURE",
    }
    如果您的 userinfo 端点返回 HTTP 200 成功响应,则系统会针对用户的 Google 账号注册检索到的令牌和声明。

    userinfo 端点响应
    sub 系统中用于识别用户的唯一 ID。
    email 用户的电子邮件地址。
    given_name 可选:用户的名字。
    family_name 可选:用户的姓氏。
    name 可选:用户的全名。
    picture 可选:用户的个人资料照片。

구현 확인

您可以使用 OAuth 2.0 Playground 工具验证您的实现。

在该工具中,执行以下步骤:

  1. 点击配置 以打开 OAuth 2.0 配置窗口。
  2. OAuth flow 字段中,选择 Client-side(客户端)。
  3. OAuth 端点字段中,选择自定义
  4. 在相应字段中指定您的 OAuth 2.0 端点和您分配给 Google 的客户端 ID。
  5. 第 1 步部分,不要选择任何 Google 范围。请将此字段留空或输入对服务器有效的范围(如果您不使用 OAuth 范围,则可以输入任意字符串)。完成后,点击授权 API
  6. Step 2Step 3 部分中,完成 OAuth 2.0 流程,并验证每个步骤是否按预期运行。

您可以使用 Google 账号关联演示版工具验证您的实现。

在该工具中,执行以下步骤:

  1. 点击使用 Google 账号登录按钮。
  2. 选择您要关联的账号。
  3. 输入服务 ID。
  4. (可选)输入您要请求访问权限的一个或多个范围。
  5. 点击开始演示
  6. 当系统提示时,请确认您同意或拒绝关联请求。
  7. 确认您已被重定向到您的平台。