5

我正在尝试实现“使用 Google 登录”按钮,如此处所述: https ://developers.google.com/identity/gsi/web/guides/display-button

我对它的期望感到困惑,data-login_uri如下图所示(取自上面链接的文档):

<div id="g_id_onload"
     data-client_id="YOUR_GOOGLE_CLIENT_ID"
     data-login_uri="https://your.domain/your_login_endpoint"
     data-auto_prompt="false">
</div>

我已经正确配置了我的应用程序的客户端 ID,并且我可以通过 Google 弹出窗口提供的大部分登录/身份验证流程。但是,一旦弹出窗口关闭,它就会尝试POST到我指定为data-login_uri.

这让我相信我们需要一个后端端点来做……某事……但我无法找到任何关于这个端点应该如何表现的文档,因此我不确定有什么要求与我的后端开发人员交流。

我错过了什么?

4

2 回答 2

2

TL;DR 您需要在您的服务器上安装一个后端进程(用 PHP、Python、Node 等编写脚本),该进程可以将 token_id(从div您引用的地址接收)中继到 Google 进行验证。

为什么?

谷歌的文档说:

警告:不要在后端服务器上接受普通用户 ID,例如可以通过 GoogleUser.getId() 方法获得的用户 ID。修改后的客户端应用程序可以将任意用户 ID 发送到您的服务器以模拟用户,因此您必须改为使用可验证的 ID 令牌来安全地获取服务器端登录用户的用户 ID。

细节

data-auto_prompt参数的值应指向 API 的端点或后端的可执行 CGI 进程。

假设您的域名是“example.com”。需要有一个端点,或者该端点上的可执行 cgi 脚本能够捕获带有application/x-www-form-urlencoded编码的 POST 请求。它可能是这样的:https ://www.example.com/login 。

在这个端点,脚本/路由应该能够提取“tokenid”

Google 的文档描述了后端必须在两个地方执行的操作:

在您的服务器端验证 Google ID 令牌:

  1. 验证跨站点请求伪造 (CSRF) 令牌
  2. 验证 ID 令牌的完整性

这是使用 Flask 框架的“登录”路由的 Python 代码片段:(建议使用虚拟环境,并且需要安装两个 google api 的 pip。)

在命令行: pip install --upgrade google-api-python-client google-auth-httplib2 google-auth-oauthlib

# Required imports from google API
from google.oauth2 import id_token
from google.auth.transport import requests

@bp.route('/login', methods=['POST'])
def login():

    # Supplied by g_id_onload
    tokenid = request.form['credential']

    # Hardcoded client ID. Substitute yours.
    clientid = XXXXX

    # Display the encrypted credential
    current_app.logger.debug(f"Token = {tokenid}")
   
    try:
        idinfo = id_token.verify_oauth2_token(tokenid, 
                requests.Request(), clientid)

        # Display the verified user information
        current_app.logger.debug(f"idinfo = {idinfo}")
    
        # jsonify returns a response object
        user_data = jsonify({
                'username': idinfo['email'],
                'name': idinfo['name'],
                'id': idinfo['sub']
            })
        return  user_data

    except:
        return Response(status=404)
于 2021-07-28T20:09:53.907 回答
1

此处描述了 POST 内容data-login_uri以及您在验证服务器端的 Google ID 令牌中描述的后端采取的预期操作。

强烈建议为每个请求生成一个nonce并在后端确认预期值以避免重放攻击(并且与 CSP nonce 不同以防止跨站点脚本)。

于 2021-07-30T21:41:00.320 回答