OAuth 및 Google 로그인을 사용한 간소화된 연결

개요

OAuth 기반 Google 로그인 간소화 연결OAuth 연결 외에 Google 로그인을 추가합니다. 이를 통해 Google 사용자에게 원활한 연결 환경이 제공되며 사용자가 Google 계정을 사용하여 서비스에 새 계정을 만들 수 있는 계정 생성도 가능합니다.

OAuth 및 Google 로그인을 사용하여 계정을 연결하려면 다음 일반 단계를 따르세요.

  1. 먼저 사용자에게 Google 프로필 액세스에 동의해 달라고 요청합니다.
  2. 프로필에 있는 정보를 사용하여 사용자 계정이 존재하는지 확인합니다.
  3. 기존 사용자의 경우 계정을 연결합니다.
  4. 인증 시스템에서 Google 사용자와 일치하는 결과를 찾을 수 없는 경우 Google에서 받은 ID 토큰을 검증하세요. 그러면 ID 토큰에 포함된 프로필 정보를 기반으로 사용자를 만들 수 있습니다.
이 그림은 사용자가 간소화된 연결 흐름을 사용하여 Google 계정을 연결하는 단계를 보여줍니다. 첫 번째 스크린샷은 사용자가 연결할 앱을 선택하는 방법을 보여줍니다. 두 번째 스크린샷을 통해 사용자는 서비스에 기존 계정이 있는지 확인할 수 있습니다. 세 번째 스크린샷을 통해 사용자는 연결할 Google 계정을 선택할 수 있습니다. 네 번째 스크린샷은 Google 계정을 앱과 연결하기 위한 확인입니다. 다섯 번째 스크린샷은 Google 앱에서 성공적으로 연결된 사용자 계정을 보여줍니다.

그림 1. 간소화된 연결을 통한 사용자 휴대전화의 계정 연결

간소화된 연결을 위한 요구사항

  • 기본 웹 OAuth 연결 흐름을 구현합니다. 서비스에서 OAuth 2.0을 준수하는 승인토큰 교환 엔드포인트를 지원해야 합니다.
  • 토큰 교환 엔드포인트는 JSON 웹 토큰 (JWT) 어설션을 지원하고 check, create, get 인텐트를 구현해야 합니다.

OAuth 서버 구현

토큰 교환 엔드포인트는 check, create, get 인텐트를 지원해야 합니다. 다음은 계정 연결 흐름을 통해 완료된 단계와 서로 다른 인텐트가 호출되는 시점을 보여줍니다.

  1. 사용자의 인증 시스템에 계정이 있나요? (사용자가 '예' 또는 '아니요'를 선택하여 결정)
    1. 예 : 사용자가 Google 계정과 연결된 이메일을 사용하여 플랫폼에 로그인하나요? (사용자가 '예' 또는 '아니요'를 선택하여 결정)
      1. 예 : 사용자의 인증 시스템에 일치하는 계정이 있나요? (check intent가 호출되어 확인)
        1. 예: get intent가 호출되고 가져오기 인텐트가 성공적으로 반환되면 계정이 연결됩니다.
        2. 아니요 : 새 계정을 만드시겠습니까? (사용자가 '예' 또는 '아니요'를 선택하여 결정)
          1. 예 : create intent가 호출되고 생성 인텐트가 성공적으로 반환되면 계정이 연결됩니다.
          2. 아니요 : 웹 OAuth 흐름이 트리거되고 사용자는 브라우저로 이동되며 사용자에게 다른 이메일과 연결할 수 있는 옵션이 제공됩니다.
      2. 아니요 : 웹 OAuth 흐름이 트리거되고 사용자가 사용 중인 브라우저로 이동되며 사용자에게 다른 이메일과 연결할 수 있는 옵션이 제공됩니다.
    2. 아니요 : 사용자의 인증 시스템에 일치하는 계정이 있나요? (check intent가 호출되어 확인)
      1. 예 : get intent가 호출되고 가져오기 인텐트가 성공적으로 반환되면 계정이 연결됩니다.
      2. 아니요: create intent가 호출되고 생성 인텐트가 성공적으로 반환되면 계정이 연결됩니다.

Check for an existing user account (check intent)

After the user gives consent to access their Google profile, Google sends a request that contains a signed assertion of the Google user's identity. The assertion contains information that includes the user's Google Account ID, name, and email address. The token exchange endpoint configured for your project handles that request.

If the corresponding Google account is already present in your authentication system, your token exchange endpoint responds with account_found=true. If the Google account doesn't match an existing user, your token exchange endpoint returns an HTTP 404 Not Found error with account_found=false.

The request has the following form:

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

grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&intent=check&assertion=JWT&scope=SCOPES&client_id=GOOGLE_CLIENT_ID&client_secret=GOOGLE_CLIENT_SECRET

Your token exchange endpoint must be able to handle the following parameters:

Token endpoint parameters
intent For these requests, the value of this parameter is check.
grant_type The type of token being exchanged. For these requests, this parameter has the value urn:ietf:params:oauth:grant-type:jwt-bearer.
assertion A JSON Web Token (JWT) that provides a signed assertion of the Google user's identity. The JWT contains information that includes the user's Google Account ID, name, and email address.
client_id The client ID you assigned to Google.
client_secret The client secret you assigned to Google.

To respond to the check intent requests, your token exchange endpoint must perform the following steps:

  • Validate and decode the JWT assertion.
  • Check if the Google account is already present in your authentication system.
验证并解码JWT断言

您可以使用针对您的语言JWT解码库来验证和解码JWT断言。使用Google的JWKPEM格式的公钥来验证令牌的签名。

解码后,JWT断言类似于以下示例:

{
  "sub": "1234567890",      // The unique ID of the user's Google Account
  "iss": "https://accounts.google.com",        // The assertion's issuer
  "aud": "123-abc.apps.googleusercontent.com", // Your server's client ID
  "iat": 233366400,         // Unix timestamp of the assertion's creation time
  "exp": 233370000,         // Unix timestamp of the assertion's expiration time
  "name": "Jan Jansen",
  "given_name": "Jan",
  "family_name": "Jansen",
  "email": "jan@gmail.com", // If present, the user's email address
  "email_verified": true,   // true, if Google has verified the email address
  "hd": "example.com",      // If present, the host domain of the user's GSuite email address
                            // If present, a URL to user's profile picture
  "picture": "https://lh3.googleusercontent.com/a-/AOh14GjlTnZKHAeb94A-FmEbwZv7uJD986VOF1mJGb2YYQ",
  "locale": "en_US"         // User's locale, from browser or phone settings
}

除了验证令牌的签名外,还要验证断言的颁发者( iss字段)为https://accounts.google.com ,受众( aud字段)是您分配的客户端ID,并且令牌尚未过期( exp场地)。

使用emailemail_verifiedhd字段,您可以确定Google是否托管电子邮件地址并对其具有权威性。如果Google具有权威性,则当前已知该用户为合法帐户所有者,您可以跳过密码或其他挑战方法。否则,可以使用这些方法在链接之前验证帐户。

Google具有权威性的情况:

  • email后缀为@gmail.com ,这是一个Gmail帐户。
  • email_verified为true并且设置了hd ,这是一个G Suite帐户。

用户可以在不使用Gmail或G Suite的情况下注册Google帐户。如果email不包含@gmail.com后缀,并且没有hd则Google并不具有权威性,建议您使用密码或其他验证方法来验证用户。当Google在创建Google帐户时最初验证了用户时, email_verfied也可能为true,但是此后第三方电子邮件帐户的所有权可能已更改。

Check if the Google account is already present in your authentication system

Check whether either of the following conditions are true:

  • The Google Account ID, found in the assertion's sub field, is in your user database.
  • The email address in the assertion matches a user in your user database.

If either condition is true, the user has already signed up. In that case, return a response like the following:

HTTP/1.1 200 Success
Content-Type: application/json;charset=UTF-8

{
  "account_found":"true",
}

If neither the Google Account ID nor the email address specified in the assertion matches a user in your database, the user hasn't signed up yet. In this case, your token exchange endpoint needs to reply with a HTTP 404 error that specifies "account_found": "false", as in the following example:

HTTP/1.1 404 Not found
Content-Type: application/json;charset=UTF-8

{
  "account_found":"false",
}

자동 연결 처리 (인텐트 가져오기)

사용자가 Google 프로필에 액세스하는 데 동의하면 Google에서는 Google 사용자의 서명된 어설션이 포함된 요청을 보냅니다. 어설션에는 사용자의 Google 계정 ID, 이름, 이메일 주소가 포함된 정보가 포함됩니다. 프로젝트에 구성된 토큰 교환 엔드포인트가 해당 요청을 처리합니다.

해당하는 Google 계정이 이미 인증 시스템에 있는 경우 토큰 교환 엔드포인트는 사용자의 토큰을 반환합니다. Google 계정이 기존 사용자와 일치하지 않으면 토큰 교환 엔드포인트가 linking_error 오류와 선택적 login_hint를 반환합니다.

요청의 형식은 다음과 같습니다.

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

grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&intent=get&assertion=JWT&scope=SCOPES&client_id=GOOGLE_CLIENT_ID&client_secret=GOOGLE_CLIENT_SECRET

토큰 교환 엔드포인트는 다음 매개변수를 처리할 수 있어야 합니다.

토큰 엔드포인트 매개변수
intent 이러한 요청의 경우 이 매개변수의 값은 get입니다.
grant_type 교환되는 토큰의 유형입니다. 이러한 요청의 경우 이 매개변수의 값은 urn:ietf:params:oauth:grant-type:jwt-bearer입니다.
assertion Google 사용자 ID의 서명된 어설션을 제공하는 JSON 웹 토큰 (JWT)입니다. JWT에는 사용자의 Google 계정 ID, 이름, 이메일 주소가 포함된 정보가 포함됩니다.
scope 선택사항: 사용자에게 요청하도록 구성한 모든 범위입니다.
client_id Google에 할당한 클라이언트 ID
client_secret Google에 할당한 클라이언트 비밀번호

get 인텐트 요청에 응답하려면 토큰 교환 엔드포인트에서 다음 단계를 실행해야 합니다.

  • JWT 어설션의 유효성을 검사하고 디코딩합니다.
  • 인증 시스템에 Google 계정이 이미 있는지 확인합니다.
验证并解码JWT断言

您可以使用针对您的语言JWT解码库来验证和解码JWT断言。使用Google的JWKPEM格式的公钥来验证令牌的签名。

解码后,JWT断言类似于以下示例:

{
  "sub": "1234567890",      // The unique ID of the user's Google Account
  "iss": "https://accounts.google.com",        // The assertion's issuer
  "aud": "123-abc.apps.googleusercontent.com", // Your server's client ID
  "iat": 233366400,         // Unix timestamp of the assertion's creation time
  "exp": 233370000,         // Unix timestamp of the assertion's expiration time
  "name": "Jan Jansen",
  "given_name": "Jan",
  "family_name": "Jansen",
  "email": "jan@gmail.com", // If present, the user's email address
  "email_verified": true,   // true, if Google has verified the email address
  "hd": "example.com",      // If present, the host domain of the user's GSuite email address
                            // If present, a URL to user's profile picture
  "picture": "https://lh3.googleusercontent.com/a-/AOh14GjlTnZKHAeb94A-FmEbwZv7uJD986VOF1mJGb2YYQ",
  "locale": "en_US"         // User's locale, from browser or phone settings
}

除了验证令牌的签名外,还要验证断言的颁发者( iss字段)为https://accounts.google.com ,受众( aud字段)是您分配的客户端ID,并且令牌尚未过期( exp场地)。

使用emailemail_verifiedhd字段,您可以确定Google是否托管电子邮件地址并对其具有权威性。如果Google具有权威性,则当前已知该用户为合法帐户所有者,您可以跳过密码或其他挑战方法。否则,可以使用这些方法在链接之前验证帐户。

Google具有权威性的情况:

  • email后缀为@gmail.com ,这是一个Gmail帐户。
  • email_verified为true并且设置了hd ,这是一个G Suite帐户。

用户可以在不使用Gmail或G Suite的情况下注册Google帐户。如果email不包含@gmail.com后缀,并且没有hd则Google并不具有权威性,建议您使用密码或其他验证方法来验证用户。当Google在创建Google帐户时最初验证了用户时, email_verfied也可能为true,但是此后第三方电子邮件帐户的所有权可能已更改。

인증 시스템에 Google 계정이 이미 있는지 확인하기

다음 조건 중 하나에 해당하는지 확인합니다.

  • 어설션의 sub 필드에 있는 Google 계정 ID는 사용자 데이터베이스에 있습니다.
  • 어설션의 이메일 주소가 사용자 데이터베이스의 사용자와 일치합니다.

사용자의 계정이 발견되면 액세스 토큰을 발급하고 다음 예와 같이 HTTPS 응답 본문에 JSON 객체의 값을 반환합니다.

{
  "token_type": "Bearer",
  "access_token": "ACCESS_TOKEN",

  "refresh_token": "REFRESH_TOKEN",

  "expires_in": SECONDS_TO_EXPIRATION
}

경우에 따라 ID 토큰 기반의 계정 연결에 실패할 수 있습니다. 어떠한 경우든 다음 예와 같이 토큰 교환 엔드포인트에서 error=linking_error를 지정하는 HTTP 401 오류로 응답해야 합니다.

HTTP/1.1 401 Unauthorized
Content-Type: application/json;charset=UTF-8

{
  "error":"linking_error",
  "login_hint":"foo@bar.com"
}

Google에서 linking_error와 함께 401 오류 응답을 받으면 Google은 login_hint를 매개변수로 사용하여 사용자를 승인 엔드포인트로 보냅니다. 사용자가 브라우저에서 OAuth 연결 흐름을 사용하여 계정 연결을 완료합니다.

通过 Google 登录功能创建帐号(创建 intent)

当用户需要在您的服务上创建帐号时,Google 会向您的令牌交换端点发出请求,并指定 intent=create

请求的格式如下:

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

response_type=token&grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&scope=SCOPES&intent=create&assertion=JWT&client_id=GOOGLE_CLIENT_ID&client_secret=GOOGLE_CLIENT_SECRET

您的令牌交换端点必须能够处理以下参数:

令牌端点参数
intent 对于这些请求,此参数的值为 create
grant_type 要交换的令牌的类型。对于这些请求,此参数的值为 urn:ietf:params:oauth:grant-type:jwt-bearer
assertion 一个 JSON Web 令牌 (JWT),用于提供 Google 用户身份的签名断言。JWT 包含用户的 Google 帐号 ID、姓名和电子邮件地址等信息。
client_id 您分配给 Google 的客户端 ID。
client_secret 您分配给 Google 的客户端密钥。

assertion 参数中的 JWT 包含用户的 Google 帐号 ID、名称和电子邮件地址,您可以使用这些信息在服务中创建新帐号。

为了响应 create intent 请求,您的令牌交换端点必须执行以下步骤:

  • 验证并解码 JWT 断言。
  • 验证用户信息并创建新帐号。
验证并解码JWT断言

您可以使用针对您的语言JWT解码库来验证和解码JWT断言。使用Google的JWKPEM格式的公钥来验证令牌的签名。

解码后,JWT断言类似于以下示例:

{
  "sub": "1234567890",      // The unique ID of the user's Google Account
  "iss": "https://accounts.google.com",        // The assertion's issuer
  "aud": "123-abc.apps.googleusercontent.com", // Your server's client ID
  "iat": 233366400,         // Unix timestamp of the assertion's creation time
  "exp": 233370000,         // Unix timestamp of the assertion's expiration time
  "name": "Jan Jansen",
  "given_name": "Jan",
  "family_name": "Jansen",
  "email": "jan@gmail.com", // If present, the user's email address
  "email_verified": true,   // true, if Google has verified the email address
  "hd": "example.com",      // If present, the host domain of the user's GSuite email address
                            // If present, a URL to user's profile picture
  "picture": "https://lh3.googleusercontent.com/a-/AOh14GjlTnZKHAeb94A-FmEbwZv7uJD986VOF1mJGb2YYQ",
  "locale": "en_US"         // User's locale, from browser or phone settings
}

除了验证令牌的签名外,还要验证断言的颁发者( iss字段)为https://accounts.google.com ,受众( aud字段)是您分配的客户端ID,并且令牌尚未过期( exp场地)。

使用emailemail_verifiedhd字段,您可以确定Google是否托管电子邮件地址并对其具有权威性。如果Google具有权威性,则当前已知该用户为合法帐户所有者,您可以跳过密码或其他挑战方法。否则,可以使用这些方法在链接之前验证帐户。

Google具有权威性的情况:

  • email后缀为@gmail.com ,这是一个Gmail帐户。
  • email_verified为true并且设置了hd ,这是一个G Suite帐户。

用户可以在不使用Gmail或G Suite的情况下注册Google帐户。如果email不包含@gmail.com后缀,并且没有hd则Google并不具有权威性,建议您使用密码或其他验证方法来验证用户。当Google在创建Google帐户时最初验证了用户时, email_verfied也可能为true,但是此后第三方电子邮件帐户的所有权可能已更改。

验证用户信息并创建新帐号

检查是否满足以下任一条件:

  • Google 帐号 ID 可在用户的数据库中找到,可在断言的 sub 字段找到。
  • 断言中的电子邮件地址与您的用户数据库中的用户匹配。

如果任一条件为 true,请提示用户将其现有帐号与其 Google 帐号相关联。为此,请对请求进行响应,并提供指定 error=linking_error 并将用户的电子邮件地址作为 login_hint 的 HTTP 401 错误。以下是一个示例响应:

HTTP/1.1 401 Unauthorized
Content-Type: application/json;charset=UTF-8

{
  "error":"linking_error",
  "login_hint":"foo@bar.com"
}

Google 收到包含 linking_error 的 401 错误响应后,会将用户作为授权参数 login_hint 发送到您的授权端点。用户在浏览器中使用 OAuth 关联流程完成帐号关联。

如果两个条件都不满足,请使用 JWT 中提供的信息创建新的用户帐号。新帐号通常不会设置密码。建议您将 Google 登录功能添加到其他平台,以便用户能够在应用界面使用 Google 帐号登录。或者,您也可以通过电子邮件向用户发送一个启动密码恢复流程的链接,以便用户设置密码以在其他平台上登录。

创建完成后,发出访问令牌 和刷新令牌 ,并在 HTTPS 响应的正文中以 JSON 对象形式返回值,如以下示例所示:

{
  "token_type": "Bearer",
  "access_token": "ACCESS_TOKEN",

  "refresh_token": "REFRESH_TOKEN",

  "expires_in": SECONDS_TO_EXPIRATION
}

Google API 클라이언트 ID 가져오기

계정 연결 등록 과정 중에 Google API 클라이언트 ID를 제공해야 합니다.

OAuth 연결 단계를 완료하는 동안 만든 프로젝트를 사용하여 API 클라이언트 ID를 가져옵니다. 그러려면 다음 단계를 완료하세요.

  1. Google API 콘솔사용자 인증 정보 페이지를 엽니다.
  2. Google API 프로젝트를 만들거나 선택합니다.

    프로젝트에 웹 애플리케이션 유형의 클라이언트 ID가 없으면 사용자 인증 정보 만들기 > OAuth 클라이언트 ID를 클릭하여 클라이언트 ID를 만듭니다. 승인된 자바스크립트 원본 상자에 사이트의 도메인을 포함해야 합니다. 로컬 테스트 또는 개발을 실행할 때 승인된 자바스크립트 원본 필드에 http://localhosthttp://localhost:<port_number>를 모두 추가해야 합니다.

구현 확인

당신은 사용하여 구현을 확인할 수 의 OAuth 2.0 놀이터 도구를.

도구에서 다음 단계를 수행합니다.

  1. 구성을 클릭 의 OAuth 2.0 구성 창을 엽니 다.
  2. 의 OAuth 흐름 필드에 클라이언트 측을 선택합니다.
  3. OAuth를 엔드 포인트 필드에서 사용자 지정을 선택합니다.
  4. 해당 필드에 OAuth 2.0 엔드포인트와 Google에 할당한 클라이언트 ID를 지정합니다.
  5. 1 단계 섹션에서 모든 Google 범위를 선택하지 마십시오. 대신 이 필드를 비워 두거나 서버에 유효한 범위를 입력하십시오(OAuth 범위를 사용하지 않는 경우 임의의 문자열). 작업이 완료되면, API 승인을 클릭합니다.
  6. 단계 2단계 3 부에서의 OAuth 2.0 유동 통과 의도 한대로 각 단계가 제대로 작동하는지 확인.

당신은 사용하여 구현을 검증 할 수 있습니다 구글 계정에 연결하면 데모 도구를.

도구에서 다음 단계를 수행합니다.

  1. 로그인 구글 버튼을 클릭합니다.
  2. 연결할 계정을 선택합니다.
  3. 서비스 ID를 입력합니다.
  4. 선택적으로 액세스를 요청할 하나 이상의 범위를 입력합니다.
  5. 시작 데모를 클릭합니다.
  6. 메시지가 표시되면 연결 요청에 동의하고 거부할 수 있는지 확인합니다.
  7. 플랫폼으로 리디렉션되었는지 확인합니다.