【React】Google 账号之个性化一键登录按钮功能

news2024/11/17 0:05:30

在这里插入图片描述

“使用 Google 帐号登录”功能可快速管理网站上的用户身份验证。用户登录 Google 账号、表示同意,并安全地与平台共享其个人基础资料信息。

  • 官方文档:链接

一、获取 Google API 客户端 ID

  1. 打开 Google API 控制台 中的凭据页面

  2. 创建或选择 Google API 项目。

  3. 点击创建凭据 > OAuth 客户端 ID,对于应用类型,选择 Web 应用以创建新的客户端 ID。
    在这里插入图片描述

  4. 将您网站的 URI 添加到已获授权的 JavaScript 来源中。URI 仅包含架构和完全限定的主机名。例如 https://www.example.com

  • 对于本地测试或开发,请同时添加 http://localhosthttp://localhost:<port_number>
  • Google 一键快捷功能只能在 HTTPS 网域中显示。
  1. (可选)使用重定向到托管的端点(而不是通过 JavaScript 回调)返回凭据。在这种情况下,请将重定向 URI 添加到已获授权的重定向 URI 中。重定向 URI 包含 scheme、完全限定主机名和路径,并且必须符合重定向 URI 验证规则。例如 https://www.example.com/auth-receiver

    在这里插入图片描述

二、加载客户端库

在需要用到的页面上载入客户端库
<script src="https://accounts.google.com/gsi/client" async></script>

由于,我们需要在react项目中引用,后面会有个简单的组件来实现调用

三、集成代码

HTML版

官方提供了在线HTML集成代码生成器:链接

  • 《“使用 Google 帐号登录”HTML API 参考文档》

在这里插入图片描述
生成代码如下(仅供参考):

<div id="g_id_onload"
     data-client_id="testid"
     data-context="signin"
     data-ux_mode="popup"
     data-login_uri="http://localhost/login"
     data-auto_prompt="false">
</div>

<div class="g_id_signin"
     data-type="standard"
     data-shape="rectangular"
     data-theme="outline"
     data-text="signin_with"
     data-size="large"
     data-logo_alignment="left">
</div>

支持的数据属性:

属性说明
data-client_id您的应用的客户端 ID
data-auto_prompt显示 Google One 点按信息。
data-auto_select为 Google 一键启用自动选择功能。
data-login_uri登录端点的网址
data-callbackJavaScript ID 令牌处理程序函数名称
data-native_login_uri密码凭据处理程序端点的网址
data-native_callbackJavaScript 密码凭据处理程序函数名称
data-native_id_paramcredential.id 值的参数名称
data-native_password_paramcredential.password 值的参数名称
data-cancel_on_tap_outside控制当用户在提示之外点击时是否取消提示。
data-prompt_parent_id一键式提示容器元素的 DOM ID
data-skip_prompt_cookie如果指定的 Cookie 具有非空值,则跳过一次点按。
data-nonceID 令牌的随机字符串
data-context一键式提示中的标题和字词
data-moment_callback提示界面状态通知监听器的函数名称
data-state_cookie_domain如果您需要在父网域及其子网域中调用一键快捷功能,请将父网域传递给此属性,以便使用单个共享 Cookie。
data-ux_mode“使用 Google 账号登录”按钮用户体验流程
data-allowed_parent_origin可以嵌入中间 iframe 的来源。如果存在此属性,则一键快捷功能会在中间 iframe 模式下运行。
data-intermediate_iframe_close_callback当用户手动关闭一键式按钮时,替换默认的中间 iframe 行为。
data-itp_support在 ITP 浏览器上启用升级后的一键式用户体验。
data-login_hint通过提供用户提示跳过账号选择。
data-hd按网域限制帐号选择。
data-use_fedcm_for_prompt允许浏览器控制用户登录提示并在您的网站和 Google 之间协调登录流程。

JavaScript版

《“使用 Google JavaScript API 参考文档》

初始化方法:google.accounts.id.initialize

google.accounts.id.initialize(IdConfiguration)

支持数据类型(IdConfiguration):

属性说明
client_id您的应用的客户端 ID
auto_select启用自动选择功能。
callback处理 ID 令牌的 JavaScript 函数。Google 一键快捷功能和“使用 Google 账号登录”按钮 popup 用户体验模式会使用此属性。
login_uri登录端点的网址。“使用 Google 账号登录”按钮 redirect 用户体验模式会使用此属性。
native_callback处理密码凭据的 JavaScript 函数。
cancel_on_tap_outside在用户点击提示之外的位置时取消提示。
prompt_parent_id一键式提示容器元素的 DOM ID
nonceID 令牌的随机字符串
context一键式提示中的标题和字词
state_cookie_domain如果您需要在父网域及其子网域中调用一键快捷功能,请将父网域传递给此字段,以便使用单个共享 Cookie。
ux_mode“使用 Google 账号登录”按钮用户体验流程
allowed_parent_origin可以嵌入中间 iframe 的来源。如果存在此字段,则会在中间 iframe 模式下运行一键快捷功能。
intermediate_iframe_close_callback当用户手动关闭一键式按钮时,替换默认的中间 iframe 行为。
itp_support在 ITP 浏览器上启用升级后的一键式用户体验。
login_hint通过提供用户提示跳过账号选择。
hd按网域限制帐号选择。
use_fedcm_for_prompt允许浏览器控制用户登录提示,并在您的网站和 Google 之间协调登录流程。

更多详细用法,可以查阅官方文档


四、react项目中集成

环境

  • react: ^18
  • react-i18next:^14.0.5
  • next: 14.1.0

按钮语言根据浏览器当前语言自动切换
在这里插入图片描述

展示&调用部分

// file: ./component/Google/index.tsx
"use client";

import { useEffect } from "react";
import { useTranslation } from "react-i18next";
import { AuthServerConfigs } from "@/configs/server.configs";
import { GoogleVerify } from "./GoogleServer";
import Logs from "@/utils/logs";

type GoogleCallbackProps = {
  clientId?: string;
  client_id?: string;
  credential: string; // 返回的 ID 令牌
  select_by: string; // 凭据的选择方式 @link https://developers.google.cn/identity/gsi/web/reference/js-reference?hl=zh-cn#select_by
};

let _alphaTabInstance: any = null;

// 载入或卸载Google库资源
function loadGoogleGsi(isLoad: boolean) {
  const scriptId = "google-gsi";
  if (isLoad && !_alphaTabInstance) {
    _alphaTabInstance = true;

    const script = document.createElement("script");
    script.id = scriptId;
    script.src = "https://accounts.google.com/gsi/client";

    return new Promise((resolve, reject) => {
      script.onload = () => {
        _alphaTabInstance = true;
        resolve(void 0);
      };
      script.onerror = (error) => {
        Logs.error("Error: ", error);
        _alphaTabInstance = false;
        reject(error);
      };
      document.head.appendChild(script);
    });
  } else {
    const ele = document.getElementById(scriptId);
    const eleService = document.getElementById("googleidentityservice");
    const eleStyles = document.getElementById(
      "googleidentityservice_button_styles"
    );
    ele && ele.remove();
    eleService && eleService.remove();
    eleStyles && eleStyles.remove();
    _alphaTabInstance = false;
  }
}

/**
 * 库初始化及样式
 * @link https://developers.google.cn/identity/gsi/web/reference/js-reference?hl=zh-cn#IdConfiguration
 */
const GoogleSignIn = function (props: {
  clientId: string;
  callback?: (props: GoogleCallbackProps) => void;
  cancel?: (props: GoogleCallbackProps) => void;
}) {
  const buttonId = "google-login-button";
  const buttonConfig = {
    theme: "outline",
    size: "large",
    text: "login_with",
    shape: "rectangular",
    width: 351,
  };
  const IdConfiguration = {
    client_id: props.clientId,
    use_fedcm_for_prompt: true,
    cancel_on_tap_outside: true, // 控制是否在提示之外进行点击时取消提示(关闭一键登录弹窗),默认true
    auto_select: false, // 开启自动登录功能,默认false
    login_uri: "https://localhost:8080/api/bcc/auth/login",
    context: "use",
    // state_cookie_domain: "localhost",
    ux_mode: "redirect",
    itp_support: true,
    callback: props?.callback || undefined, // 验证成功回调
    cancel: props?.cancel || undefined,
  };

  useEffect(() => {
    // @ts-ignore
    if (!window.google) {
      loadGoogleGsi(true)?.then(() => {
        // @ts-ignore
        const googleApi = window.google;
        try {
          googleApi.accounts.id.initialize(IdConfiguration);
          // 渲染“使用 Google 帐号登录”按钮
          googleApi.accounts.id.renderButton(
            document.getElementById(buttonId),
            buttonConfig
          );
          // 启用一键登录提示(弹窗)功能
          googleApi.accounts.id.prompt();

          // setTimeout(()=>{
          //   googleApi.accounts.id.disableAutoSelect();
          // }, 5000)
        } catch (e) {
          Logs.debug("googleApi->Initialized Error:", e);
        }
      });
    }

    return () => {
      loadGoogleGsi(false);
      // @ts-ignore
      window.google = undefined;
    };
  }, []);

  return (
    <>
      <div id={buttonId}></div>
    </>
  );
};

// 上层调用
const Channel = function () {
  const { i18n } = useTranslation();

  function handleGoogleSignIn(props: GoogleCallbackProps) {
    GoogleVerify(AuthServerConfigs.Google.clientId, props.credential)
      .then((res) => {
        console.log("handleGoogleSignIn->then:", res);
      })
      .catch((err) => {
        console.log("handleGoogleSignIn->catch:", err);
      });
  }

  function handleGoogleSignInCancel(props: GoogleCallbackProps) {
    console.log("handleGoogleSignInCancel:", props);
  }

  return (
    <>
      {i18n.language === "en" && (
        <GoogleSignIn
          clientId={AuthServerConfigs.Google.clientId}
          callback={handleGoogleSignIn}
          cancel={handleGoogleSignInCancel}
        />
      )}
    </>
  );
};

export const GoogleChannel = Channel;
export default Channel;

回调验证部分

安装依赖库:google-auth-library

npm install google-auth-library
# or
pnpm add google-auth-library
"use server";

import { OAuth2Client } from "google-auth-library";
import { AuthServerConfigs } from "@/configs/server.configs";

const client = new OAuth2Client({
  clientId: AuthServerConfigs.Google.clientId,
  clientSecret: AuthServerConfigs.Google.clientSecret,
});
/**
 *
 * @link https://developers.google.cn/identity/gsi/web/guides/verify-google-id-token?hl=zh-cn
 * @param clientId
 * @param token
 */
export async function GoogleVerify(clientId: string | string[], token: string) {
  return new Promise((resolve, reject) => {
    client
      .verifyIdToken({
        idToken: token,
        audience: clientId, // 指定访问后端的应用程序的CLIENT_ID
        // 或者,如果多个客户端访问后端:[CLIENT_ID_1, CLIENT_ID_2, CLIENT_ID_3]
      })
      .then((ticket) => {
        console.log("ticket:", ticket);
        const payload: any = ticket.getPayload();
        console.log("payload:", payload);
        const userid = payload["sub"];
        resolve({ userid, payload });
      })
      .catch((error) => {
        reject(error);
      });
  });
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1909268.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

小米采取措施禁止国行版设备安装国际版系统 刷机后将报错无法进入系统

据知名官改版系统 Xiaomi.EU 测试者 Kacper Skrzypek 发布的消息&#xff0c;小米目前已经在开机引导中新增区域检测机制&#xff0c;该机制将识别硬件所属的市场版本&#xff0c;例如中国大陆市场销售的小米即将在安装国际版系统后将无法正常启动。 测试显示该检测机制是在开…

有浏览器就行,手把手带你从零微调大模型!

有浏览器就行&#xff0c;手把手带你从零微调大模型&#xff01; 今天分享一篇技术文章&#xff0c;你可能听说过很多大模型的知识&#xff0c;但却从未亲自使用或微调过大模型。 今天这篇文章&#xff0c;就手把手带你从零微调一个大模型。 大模型微调本身是一件非常复杂且…

自动化测试全攻略:从入门到精通!

1、自动化测试专栏 随着技术的发展和工作需求的增长&#xff0c;自动化测试已成为软件质量保障体系中不可或缺的一环。 为了帮助广大测试工程师、开发者和对自动化测试感兴趣的读者们更好地掌握这一技能&#xff0c;今年特别推出了全新的《自动化测试全攻略&#xff1a;从入门…

[Python爬虫] 抓取京东商品数据||京东商品API接口采集

本文结构&#xff1a; 一、引言 二、代码分享 三、问题总结 引言 这两天因为一些需求&#xff0c;研究了一下如何爬取京东商品数据。最开始还是常规地使用selenium库进行商品页的商品抓取&#xff0c;后来因为想要获取优惠信息&#xff0c;只能进入到商品详情页进行抓取&#x…

阶段三:项目开发---民航功能模块实现:任务24:航空实时监控

任务描述 内 容&#xff1a;地图展示、飞机飞行轨迹、扇区控制。航空实时监控&#xff0c;是飞机每秒发送坐标&#xff0c;经过终端转换实时发送给塔台&#xff0c;为了飞机位置的精准度&#xff0c;传输位置的密度很大&#xff0c;在地图位置显示不明显。本次为了案例展示效…

如何成功的设计BGA?

目前&#xff0c;用于容纳各种先进多功能半导体器件&#xff08;如 FPGA 和微处理器&#xff09;的标准封装是球栅阵列 &#xff08;BGA&#xff09;。BGA 封装中的组件用于各种嵌入式设计中&#xff0c;既可用作主机处理器&#xff0c;也可用作存储器等外设。多年来&#xff0…

抖音机构号授权源码全解析

抖音机构号授权源码是抖音平台为了方便机构用户进行授权管理而推出的一项服务。随着抖音平台的快速发展&#xff0c;越来越多的机构开始意识到抖音作为一种强大的营销渠道的价值。为了更好地利用抖音平台的资源&#xff0c;许多机构开始了解抖音机构号的功能和优势&#xff0c;…

css 文件重复类样式删除

上传文件 进行无关 className 删除 <div style"display: flex;"><input type"file" change"handleFileUpload" /><el-button click"removeStyles" :disabled"!fileContent">Remove Styles and Download&…

科普文:Linux服务器常用命令和脚本

Linux服务器常用的命令&#xff1a;find、grep、xargs、sort、uniq、tr、cut、paste、wc、sed、awk&#xff1b;提供的例子和参数都是最常用和最为实用的。 1.find 文件查找 查找txt和pdf文件 find . \( -name "*.txt" -o -name "*.pdf" \) -print 正…

VS2019 因公司加密无法运行程序原因

问题原因&#xff0c;点击编译运行按钮出现以下问题 首先右击项目&#xff0c;然后点击属性&#xff0c;点击应用程序&#xff0c;将资源里面的清单修改为 创建不带清单的应用程序&#xff0c;即可

竞速赛车游戏推荐:极品飞车14:热力追踪 (Win/Mac) 安装包

《极品飞车14&#xff1a;热力追踪》&#xff08;Need for Speed: Hot Pursuit&#xff09;是《极品飞车》系列的第14部作品&#xff0c;于2010年11月发行。这款游戏是继《极品飞车&#xff1a;热力追踪2》后&#xff0c;系列再次回归该名称。 游戏采用 Criterion Games 的开放…

STM32的独立看门狗详解

目录 1.独立看门狗是什么&#xff1f; 2.独立看门狗的作用 3.独立看门狗的实现原理 4.独立看门狗用到的寄存器 4.1 IWDG_KR &#xff08;关键字计时器&#xff09; 4.2 IWDG_PR&#xff08;预分频寄存器&#xff09; 4.3 IWDG_RLR&#xff08;重装载寄存器&#xff09…

土壤水分及其频谱分析

祁连山综合观测网&#xff1a;黑河流域地表过程综合观测网&#xff08;混合林站自动气象站-2018&#xff09; import pandas as pd dfpd.read_excel(rC:\Users\mengx\Desktop\土壤水分的频谱分析\祁连山综合观测网&#xff1a;黑河流域地表过程综合观测网&#xff08;混合林站…

RocketMQ之消费者,重平衡机制与流程详解附带源码解析

1. 背景 本文是 RocketMQ 消费者系列的第三篇&#xff0c;介绍消费者重平衡。 我把 RocketMQ 消费分成如下几个步骤 重平衡 消费者拉取消息 Broker 接收拉取请求后从存储中查询消息并返回 消费者消费消息 其中重平衡是消费者开始消费的起点。 1.1 重平衡的含义 RocketMQ 的 To…

【单片机毕业设计选题24052】-基于STM32的智能书桌设计

系统功能: 基于stm32单片机的智能书桌设计 1.手动&#xff1a;升降桌&#xff0c;调整桌面高度&#xff0c;实现升降功能&#xff0c; 2.自动&#xff1a;光敏控制灯的亮度 手动&#xff1a;开关灯 3.自动&#xff1a;检测学习姿势报警&#xff0c;超声波检测人是否坐的太…

【单片机毕业设计选题24051】-基于STM32的温室大棚控制系统

系统功能: 1、检测环境温湿度&#xff0c;土壤湿度&#xff0c;光照强度和二氧化碳浓度并在OLED和APP上显示。 2、当空气温度过高时则打开风扇通风。 3、当空气湿度过低时打开加湿器加湿。 4、土壤湿度过低&#xff0c;打开水泵。 5、光照不足则打开LED,反之则关闭…

麒麟系统设置中添加打印机按钮无响应的解决办法

原文链接&#xff1a;麒麟系统设置中添加打印机按钮无响应的解决办法 Hello&#xff0c;大家好啊&#xff01;今天给大家带来一篇关于在麒麟桌面操作系统上点击设置中的添加打印机按钮无响应的解决办法的文章。打印机是我们日常办公的重要工具&#xff0c;如果添加打印机按钮无…

昇思25天学习打卡营第15天|应用实践之ShuffleNet图像分类

基本介绍 今天的应用实践的领域是计算机视觉领域&#xff0c;更确切的说是图像分类任务&#xff0c;不过&#xff0c;与昨日不同的是&#xff0c;今天所使用的模型是ShuffleNet模型。ShuffleNetV1是旷视科技提出的一种计算高效的CNN模型&#xff0c;和MobileNet, SqueezeNet等一…

柳永,市井生活的吟游者

柳永&#xff0c;原名柳三变&#xff0c;字景庄&#xff0c;后改名为柳永&#xff0c;字耆卿&#xff0c;约生于宋太宗雍熙元年&#xff08;公元984年&#xff09;&#xff0c;卒于宋仁宗皇祐五年&#xff08;公元1053年&#xff09;&#xff0c;享年69岁。他是北宋著名词人&am…

最近换工作的一些启示,清华学姐篇

最近更新频率慢下来了&#xff0c;一部分原因是沉迷运动不能自拔&#xff0c;还有一部分原因是业余分出来很大的精力来拓展个人的边界&#xff0c;希望在工作之外取得一些成绩&#xff0c;写作上耽误了不少&#xff0c;很难做到日更。 所以整体上今年更新频率较低&#xff0c;但…