接入谷歌登录注册

谷歌授权登录注册调研

一、背景

鉴于项目需要面向海外用户,希望增加Google账户一键授权来注册/登陆产品,以获得更好的用户体验

三、登录流程

四、正确的接入姿势

1. google控制台配置

相关资料:google控制台配置最佳实践 google控制台

2. client端代码接入

参考官方javacript接入文档,同时支持HTML方式和Javascript方式的接入,经实践,vue项目更加推荐使用javascript方式接入(HTML接入存在js脚本加载顺序导致登录框初始化失败等问题,需要更复杂的处理)。 以下是以组件方式注入

o 主要逻辑包括:

  1. 加载谷歌平台库

  2. 初始化谷歌登录按钮+登录弹窗

  3. 添加用户登录回调

  4. 用户通过google授权成功后将结果传给BFF处理

xml 复制代码
    <template lang="pug">
    div.ya-login-google
        div#google-login
    </template>
     
    <script>
    import { userLoginByGoogle } from '@/query/user.js'
    import { googleLogin } from 'config/google.conf.js'
    export default {
        name: 'GoogleLogin',
        data () {
            return {
                options: {
                    client_id: googleLogin['GOOGLE_CLIENT_ID'],
                    callback: this.handleCredentialResponse
                }
            }
        },
        mounted () {
             //b.初始化谷歌登录按钮+登录弹窗
            this.loginPopup()
            this.renderButton()
        },
        methods: {
            /**
             * @description: google授权成功回调
             * @param {object} response 验证回调结果
             */
            async handleCredentialResponse (response) {//c.添加用户授权成功回调
                     //d.用户通过google授权成功后将结果传给BFF处理
                this.$gqlRequest({
                    ...userLoginByGoogle,
                    variables: {
                        googleCredential: JSON.stringify(response)
                    }
                }).then(res => {
                    // eslint-disable-next-line no-console
                    console.log(res)
                })
            },
            /**
             * @description: google登录弹窗
             */
            loginPopup () {
                window.google.accounts.id.initialize(this.options)
                window.google.accounts.id.prompt((notification) => {
                    if (notification.isNotDisplayed() || notification.isSkippedMoment()) {
                    // try next provider if OneTap is not displayed or skipped
                    }
                })
            },
            /**
             * @description: 登录按钮展示和配置
             */
            renderButton () {
                window.google.accounts.id.renderButton(document.getElementById('google-login'), {
                    theme: 'outline',
                    size: 'large',
                    width: 400,
                    text: 'continue_with'
                })
            },
            // 撤销身份认证
            revoke () {
                window.google.accounts.id.revoke('user@google.com', done => {})
            }
        }
    }
    </script>

google凭证响应回包包含的字段:

场地
credential 此字段是返回的 ID Token。
select_by 此字段设置选择凭据的方式。
bash 复制代码
解析credential获得用户信息
curl https://oauth2.googleapis.com/tokeninfo?id_token=XXX 

注意:虽然这里前端是可以通过解析credential 获得用户信息。但是不要将解析后的用户信息直接传递给后端接口,因为后端程序无法确定这个ID是用户真正通过登录得到的,还是其他某人的ID。所以正确使用token的姿势是不解析并直接将它传给后端去解析。

3. BFF端接入

主要步骤: 1、使用google服务 验证client 产生的Token 2、处理验证结果

csharp 复制代码
 loginByGoogle: async (_, args, { dataSources, ctx }) => {
            //1、通过google服务验证登录信息,包括有效期等等
            const googleCredential = args?.googleCredential || {}
            const { credential, clientId } = JSON.parse(googleCredential)
            const client = new OAuth2Client(clientId)
            async function verify () {
                const ticket = await client.verifyIdToken({
                    idToken: credential,
                    audience: clientId // Specify the CLIENT_ID of the app that accesses the backend
                })
                const { payload } = ticket
                return payload
            }
            const data = await verify().catch()
                 //2、处理登录。包括旧用户关联,新用户注册
                         //3、页面跳转
            return {
                data,
                'goto': 'login success !!!! redirect somewhere.....'
            }
        },

关于credential(Token) 这个Token是一个使用谷歌私钥签名的 JWT Token。是 base64 编码的 JSON Web 令牌 (JWT) 字符串的 ID 令牌 解析 JWT Token 的库:更推荐使用google官方的client.verifyIdToken 。

json 复制代码
//JWT Token 就是一个字符串,它由 3 部分组成:头部,数据,签名。 头部是一个JSON对象,用于描述签名算法。
header
{
  "alg": "RS256",
  "kid": "f05415b13acb9590f70df862765c655f5a7a019e", // JWT signature
  "typ": "JWT"
}
//数据也是一个JSON对象,保存公共数据和用户数据。签名是前两部分的校验和,用于确保该 Token 未被修改。 
//3 个部分通过 Base64 + HMAC(常用的算法之一) 算法合并产生出一个字符串。
payload
{
  "iss": "https://accounts.google.com", // The JWT's issuer
  "nbf":  161803398874,
  "aud": "314159265-pi.apps.googleusercontent.com", // Your server's client ID
  "sub": "3141592653589793238", // The unique ID of the user's Google Account
  "hd": "gmail.com", // If present, the host domain of the user's GSuite email address
  "email": "elisa.g.beckett@gmail.com", // The user's email address
  "email_verified": true, // true, if Google has verified the email address
  "azp": "314159265-pi.apps.googleusercontent.com",
  "name": "Elisa Beckett",
                            // If present, a URL to user's profile picture
  "picture": "https://lh3.googleusercontent.com/a-/e2718281828459045235360uler",
  "given_name": "Elisa",
  "family_name": "Beckett",
  "iat": 1596474000, // Unix timestamp of the assertion's creation time
  "exp": 1596477600, // Unix timestamp of the assertion's expiration time
  "jti": "abc161803398874def"
}

如果校验通过,就可以获取到用户相关的数据

o sub 是用户的唯一ID

o email 是用户的 Email

o name 是用户的名字

o picture 是用户的头像

验证通过后,按照不同情况的处理的建议

o 未注册的电子邮件地址:如果需要,可以显示一个注册用户界面 (UI),允许用户提供其他个人资料信息,又或者直接创建用户,用户自行更新个人信息。

o 对应用户已经存在:调用后端登录接口,保存登录状态,前端跳转对应页面

到此为至,已完成谷歌登录的接入。总结接入的步骤包括:

1.google官网先配置,先创建 ClientID

2.加载谷歌平台脚本

3.添加谷歌登录按钮

4.登录回调处理

5.与后端API接口通信

6.后端解析 ID Token 中的用户数据

7.处理数据返回结果

官方js方式接入文档 :developers.google.com/identity/gs...

其他问题:

1、服务器暂时无法正常请求Google服务

Q1:解决办法

BFF端使用代理

javascript 复制代码
const gaxios = require('gaxios')
const HttpsProxyAgent = require('https-proxy-agent')
gaxios.instance.defaults = {
    agent: new HttpsProxyAgent(`${proxy_url}`)
}

测试代理是否生效

curl -x方式

perl 复制代码
$ curl -x http://127.0.0.1:7890  https://www.googleapis.com

nodejs方式:

javascript 复制代码
gaxios.request({
agent: new HttpsProxyAgent('http://127.0.0.1:7890')
url: `https://oauth2.googleapis.com/tokeninfo?id_token=${url}`
}).then(res => {
    console.log('success', res.data)
}).catch(err => {
    console.log('error', err)
})
相关推荐
清云随笔17 分钟前
axios 实现 无感刷新方案
前端
鑫宝Code19 分钟前
【React】状态管理之Redux
前端·react.js·前端框架
忠实米线27 分钟前
使用pdf-lib.js实现pdf添加自定义水印功能
前端·javascript·pdf
pink大呲花29 分钟前
关于番外篇-CSS3新增特性
前端·css·css3
少年维持着烦恼.33 分钟前
第八章习题
前端·css·html
我是哈哈hh36 分钟前
HTML5和CSS3的进阶_HTML5和CSS3的新增特性
开发语言·前端·css·html·css3·html5·web
田本初1 小时前
如何修改npm包
前端·npm·node.js
明辉光焱1 小时前
[Electron]总结:如何创建Electron+Element Plus的项目
前端·javascript·electron
牧码岛2 小时前
Web前端之汉字排序、sort与localeCompare的介绍、编码顺序与字典顺序的区别
前端·javascript·web·web前端