Vue 项目接入Google第三方登录的详细流程🚀🚀

前言

现在很多的项目都需要接入第三方登录,比如 Google / Apple / Facebook 等登录方式,尤其是出海项目,因此很有必要把接入第三方登录的完整流程研究一遍。

接入第三方登录,核心就两个步骤:1. 按照官方提供的文档进行一些必要的配置(文档一般都会提供比较详细的接入步骤) 2. 开发人员编写代码实现效果;这里以 Google 登录为例进行讲解。

开发者平台配置

首先在 Google 开发者平台 进行配置,如果没有项目的话需要新建,这块的流程搞定之后,接下来进入 凭证 页面,生成客户端 ID 用于后续的登录流程,主要的操作步骤如下:

大家可以参考文档进行操作,这里不再详细展开。实现 Google 登录主要有两种模式,分别为弹出式窗口模式、重定向模式。

弹出式窗口模式

顾名思义,在原页面弹出一个小窗口进行登录,如下图所示:

这种模式下我们需要有一个按钮,当点击的时候唤起弹窗,Google 官方允许开发者自定义登录按钮,要显示 使用 Google 账号登录 按钮,可以选择 HTML 或者 JavaScript 的方式去实现,具体可以参考该链接:developers.google.com/identity/gs...

1.使用 HTML 呈现登录按钮,并将 JWT 返回给平台的登录端点:

js 复制代码
<html>
  <body>
    <script src="https://accounts.google.com/gsi/client" async></script>
    <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>
    <div class="g_id_signin"
        data-type="standard"
        data-size="large"
        data-theme="outline"
        data-text="sign_in_with"
        data-shape="rectangular"
        data-logo_alignment="left">
    </div>
  <body>
</html>

2.使用 JavaScript 呈现登录按钮,并将 JWT 返回给 浏览器的 JavaScript 回调处理程序:

js 复制代码
<html>
  <body>
    <script src="https://accounts.google.com/gsi/client" async></script>
    <script>
      function handleCredentialResponse(response) {
        console.log("Encoded JWT ID token: " + response.credential);
      }
      window.onload = function () {
        google.accounts.id.initialize({
          client_id: "YOUR_GOOGLE_CLIENT_ID"
          callback: handleCredentialResponse
        });
        google.accounts.id.renderButton(
          document.getElementById("buttonDiv"),
          { theme: "outline", size: "large" }  // customization attributes
        );
        google.accounts.id.prompt(); // also display the One Tap dialog
      }
    </script>
    <div id="buttonDiv"></div>
  </body>
</html>

这两段代码是在 Google 开发者平台中生成的,位于 生成集成代码 页面:

自定义按钮的样式以及模式:

我们只需要将生成的代码复制到项目中使用即可:

具体的实现代码:

js 复制代码
<!-- 登录按钮 -->
<div class="oauth-item" style="display: none">
  <div id="g_id_onload" :data-client_id="clientId" data-callback="googleCallback"</div>
  <div
    class="g_id_signin"
    data-theme="outline"
    :data-width="300"
    :data-locale="en"
  ></div>
</div>

动态引入 JS 并绑定 Google 回调事件:

js 复制代码
const clientId = ref('');

const createGoogleClient = () => {
  const cb = (data: any) => {
    const params = {
      accessToken: data.credential,
      ...
    };
    loginByGoogleIdentity(params).then(res => {
      if (res) {
        // 登录成功后做一些处理
      }
    });
  };
  (window as any).googleCallback = cb;
  const s = document.createElement('script');
  s.src = 'https://accounts.google.com/gsi/client';
  document.body.appendChild(s);
};

onMounted(() => {
  createGoogleClient();
});

架构图

这里着重讲解重定向模式,官方文档也有提到,这种方式是最安全的,在该模式下,集成 Google 第三方登录的完整架构图如下:

重定向模式

在页面上准备一个按钮,点击跳转至 Google 授权登录页,跳转链接需要 client_id 以及 redirect_uri 两个字段的值。

js 复制代码
// 重定向地址
const redirectUrl = `${location.origin}/loading`;

// Google授权登录页
const targetUrl = `https://accounts.google.com/o/oauth2/v2/auth?client_id=
${clientId}&scope=https://www.googleapis.com/auth/userinfo.email
&response_type=token&redirect_uri=${redirectUrl}`;

const signUpByGoogle = () => {
  // 缓存当前页面的URL并进行跳转
  sessionStorage.setItem('ThirdLoginUrl', location.href);
  location.href = targetUrl
};

授权登录页如下:

在 Google 授权页面完成登录之后,接下来需要携带 token 返回重定向页面。

对于重定向页面,可以考虑把所有的第三方登录都重定向到同一个页面,便于管理,比如重定向至 loading 页面:

html 复制代码
<template>
  <div>Loading Page</div>
</template>

<script setup lang="ts">
import { handleThirdLogin } from '@/utils/third-login';

handleThirdLogin()
</script>

重定向页面 handleThirdLogin 方法的主要逻辑:从 URL 中获取 access_token,接着调用一遍我们系统内部的登陆接口,携带凭证 accessToken 传给后端,后端需要向 Google 服务器验证 token 的有效性,验证通过后将用户信息返回给前端:

js 复制代码
function handleThirdLogin(cb?: () => void) {
  const accessToken = takeAccessToken();
  if (accessToken) {
    return loginByGoogleAccount({
      accessToken: accessToken,
      ...
    })
    .then(res => {
      return loginCallback(res, cb);
    })
  }
  return Promise.reslove(undefined)
}

function takeAccessToken() {
  let accessToken = getValueFormHash(location?.hash?.split('&') || [], '#access_token=');
  if (!accessToken) {
    accessToken = getValueFormHash(location?.hash?.split('&') || [], '#/access_token=');
  }
  return accessToken
}

export const getValueFormHash = (hashArr: string[], key: string) => {
  return hashArr.find((e: string) => e.startsWith(key))?.split(key)?.[1];
};

此时整个登录流程已经完成,执行 loginCallback 方法,前端可以跳转至原来的页面或者其他页面,还可以根据自己项目的需求增加一些处理逻辑:

js 复制代码
const loginCallback = (res: any, cb?: () => void) => {
  if (res) {
    cb && cb();
    const targetUrl = sessionStorage.getItem('ThirdLoginUrl');
    sessionStorage.removeItem('ThirdLoginUrl')
    location.href = targetUrl;
  }
};
相关推荐
浩浩测试一下6 分钟前
渗透信息收集- Web应用漏洞与指纹信息收集以及情报收集
android·前端·安全·web安全·网络安全·安全架构
西陵32 分钟前
Nx带来极致的前端开发体验——借助CDD&TDD开发提效
前端·javascript·架构
小磊哥er43 分钟前
【前端工程化】前端工作中的业务规范有哪些
前端
ᥬ 小月亮1 小时前
webpack基础
前端·webpack
YongGit1 小时前
探索 AI + MCP 渲染前端 UI
前端·后端·node.js
慧一居士2 小时前
<script setup>中的setup作用以及和不带的区别对比
前端
RainbowSea2 小时前
NVM 切换 Node 版本工具的超详细安装说明
java·前端
读书点滴2 小时前
笨方法学python -练习14
java·前端·python
Mintopia2 小时前
四叉树:二维空间的 “智能分区管理员”
前端·javascript·计算机图形学
Mintopia3 小时前
Three.js 深度冲突:当像素在 Z 轴上玩起 "挤地铁" 游戏
前端·javascript·three.js