Google登录授权详细过程

2023-10-29

前言


这篇文章包含了google登录授权从API创建、到使用Java代码完成登录的一个完整demo。

主要为了实现google关联用户的服务,如google merchant center等。

如果仅仅需要使用google邮箱登录,建议由前端实现google登录:

1,国内网络和google服务是不通的,国内服务器需要解决网络问题,如果由前端实现google登录用户解决网络问题即可;

2,前端实现更简单

目录

了解Auth2.0

创建API服务

使用API


了解Auth3.0

google相关文档:https://developers.google.com/identity/protocols/oauth2

google账号授权登录用的就是Auth2.0协议。

举一个例子了解Auth2.0的设计模式。

  • 令牌 Token

你在公司某个周五的下午点了一杯奶茶,楼下有个需要密码才能进来的门禁,你当然不会把密码告诉配送小哥,你告诉配送小哥在门禁App登记一下访客登记卡,你同意一系列访客管理须知后,发短信验证码给他,小哥输入验证码并获得访客卡顺利进来了;

  • 授权域 Scopes

配送小哥进来后拿这访卡刷电梯,有两个电梯都能上去你所在的楼层,电梯A能到达公司的办公场所,电梯B能到达用餐室,但小哥只能使用电梯B,因为你在用餐室等着了,没必要去到办公室打扰到其他同事;

  • 令牌过期

周六的时候你又在公司同一家店点了一杯奶茶,奶茶送到时发现发现之前申请的访客卡是临时的,要重新登记,只是你发送验证码的时候不再需要经过一系列访客管理须知,因为门禁app上已经有你对配送小哥的授权记录了;

  • 离线令牌 Refresh Token

点了两次的你觉得这家店奶茶很好喝,于是你在这家店开了会员。但有时你在开会无法及时给配送小哥访客卡验证码,于是你让店家登记一个会员卡,凭这个会员卡可以直接要到访客卡,无需授权;

  • 撤销令牌

有一天你在网上冲浪看到拓海的近照,你决定戒奶,于是在门禁app上把店家的访客卡和会员卡给取消了。

创建API服务

了解完auth2.0之后,开始正式使用google的授权登录。

现在演示的是一个测试项目,google对测试项目没有强校验,所以下面信息填写可以随意。确认可行性后创建生产项目时需要进行认证。

之外,你可能需要在YouTube上传一个使用录屏视频给审核员,来演示你是利用谷歌api来完成哪一些事情的,演示视频项目内容需要为英文,如果你的项目不是英文可以在演示的时候翻译成英文

用谷歌账号注册API

https://console.cloud.google.com/

用谷歌账号登录后创建一个【test】项目

创建完项目【test】,来到控制台

题外话:如果你想使用google某些功能,可以到Api库添加Api;例如谷歌翻译,搜索并启用。(ps:google翻译api是收费的,需要一个结算管理账号)

配置同意屏

同意屏幕:用户在你的应用登录时,google展示给用户的信息,包括网站域名与logo、隐私政策

应用网域

包含四部分信息,网站域名、网站首页、隐私政策和服务条款。

范围

即授权域。这也是会在用户同意屏幕展示的。

我们需要保存邮箱账号,所以只使用/auth/userinfo/email这个授权范围

创建凭据

选择OAuth客户端ID

选择web应用,并配置授权登录后的url(url需要是https协议,尽管只是个测试项目)

创建后就获得客户端id和秘钥

使用API服务

引入maven

<dependency>
    <groupId>com.google.auth</groupId>
    <artifactId>google-auth-library-oauth2-http</artifactId>
    <version>0.22.2</version>
</dependency>

配置类

import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets;
import com.zz.saas.shoplus.portal.bean.GoogleAuthorization;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
 * google登录授权配置
 */
@Configuration
@Slf4j
public class GoogleAuthorizationConfig {
    private static final String clientId = "your client id";
    private static final  String clientSecret = "your client secret";
    private static final  String applicationName = "your application name";
    private static final  String redirectUrl = "https://test.com/google-login";


    @Bean(name = "googleAuthorization")
    public GoogleAuthorization googleFeed() {
        GoogleClientSecrets clientSecrets = null;
        try {
            GoogleClientSecrets.Details details = new GoogleClientSecrets.Details();
            details.setClientId(clientId);
            details.setClientSecret(clientSecret);
            clientSecrets = new GoogleClientSecrets();
            clientSecrets.setInstalled(details);
        } catch (Exception e) {
            log.error("authorization configuration error:{}", e.getMessage());
        }
        // 构建bean
        return GoogleAuthorization.builder()
                .googleClientSecrets(clientSecrets)
                .applicationName(applicationName)
                .redirectUrl(redirectUrl)
                .build();
    }
}

import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Collections;
import java.util.List;

/**
 * google授权
 */
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Data
public class GoogleAuthorization {
    // 应用名
    private String applicationName;
    // 重定向路径
    private String redirectUrl;
    // 应用凭证
    private GoogleClientSecrets googleClientSecrets;
    // 授权域
    private final static List<String> scopes = Collections.singletonList(
            "https://www.googleapis.com/auth/userinfo.email"
    );

    public List<String> getScopes(){
        return scopes;
    }
}

获得发起登录请求链接

// 导包信息
import com.google.api.client.auth.oauth2.BearerToken;
import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.googleapis.auth.oauth2.*;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson2.JacksonFactory;

@Autowired
private GoogleAuthorizationService googleAuthorizationService;

public String authorizingUrl() throws GeneralSecurityException, IOException {
    HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
    JsonFactory jsonFactory = JacksonFactory.getDefaultInstance();
    // 创建验证流程对象
    GoogleAuthorizationCodeFlow googleAuthorizationCodeFlow = new GoogleAuthorizationCodeFlow
            .Builder(httpTransport, jsonFactory, googleAuthorization.getGoogleClientSecrets(), googleAuthorization.getScopes())
            // AccessType为离线offline,才能获得Refresh Token
            .setAccessType("offline").build();
    if (googleAuthorizationCodeFlow != null) {
        // 返回跳转登录请求
        return googleAuthorizationCodeFlow.newAuthorizationUrl().setRedirectUri(googleAuthorization.getRedirectUrl()).build();
    }
    return null;
}

调用方法authorizingUrl,得到一个跳转的url:

https://accounts.google.com/o/oauth2/auth?access_type=offline&client_id=YourClientId&redirect_uri=https://test.com/google-login&response_type=code&scope=https://www.googleapis.com/auth/userinfo.email 

放到postman看看参数

在浏览器访问这个url,跳转到同意屏幕,可以看到之前创建api的应用信息

登录一个谷歌账号,授权之后462,因为域名是随便填的,但是主要是获得重定向后的URL

重定向URL填充了一个授权码code,接下来就可以拿这个授权码去授权了

使用授权码授权

用授权码获得登录token

// 导包信息
import com.google.api.client.auth.oauth2.BearerToken;
import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.googleapis.auth.oauth2.*;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson2.JacksonFactory;

public void authorizing(String authorizationCode) throws GeneralSecurityException, IOException {
    // 创建请求凭证
    HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
    JsonFactory jsonFactory = JacksonFactory.getDefaultInstance();
    GoogleAuthorizationCodeFlow googleAuthorizationCodeFlow = new GoogleAuthorizationCodeFlow
            .Builder(httpTransport, jsonFactory, googleAuthorization.getGoogleClientSecrets(), googleAuthorization.getScopes())
            // AccessType为离线offline,才能获得Refresh Token
            .setAccessType("offline").build();
    GoogleAuthorizationCodeTokenRequest tokenRequest = googleAuthorizationCodeFlow.newTokenRequest(authorizationCode);
    tokenRequest.setRedirectUri(googleAuthorization.getRedirectUrl());
    // 发起授权请求,获得Token和Refresh Token
    GoogleTokenResponse tokenResponse = tokenRequest.execute();
    String token = tokenResponse.getAccessToken();
    String refreshToken = tokenResponse.getRefreshToken();
    // 获得email
    String email = null;
    if (StringUtils.isNotBlank(tokenResponse.getIdToken())) {
        GoogleIdTokenVerifier idTokenVerifier = new GoogleIdTokenVerifier.Builder(googleAuthorizationCodeFlow.getTransport(), googleAuthorizationCodeFlow.getJsonFactory()).build();
       idTokenVerifier.verify(tokenResponse.getIdToken());
        GoogleIdToken googleIdToken = idTokenVerifier.verify(tokenResponse.getIdToken());
        if (googleIdToken != null && googleIdToken.getPayload() != null) {
            email = googleIdToken.getPayload().getEmail();
        }
    }
    // todo 保留账号token、refreshToken、email信息
}

Refresh Token

token的有效期为1小时,token过期之后让用户跳转到登录页重新登录就可以了;

但如果需要离线使用谷歌api时,就可以使用Refresh Token

public String refreshToken(String refreshToken) throws IOException {
    String token = null;
    // 创建刷新请求对象
    GoogleRefreshTokenRequest googleRefreshTokenRequest = new GoogleRefreshTokenRequest(
            new NetHttpTransport(),
            JacksonFactory.getDefaultInstance(),
            refreshToken,
            googleAuthorization.getGoogleClientSecrets().getDetails().getClientId(),
            googleAuthorization.getGoogleClientSecrets().getDetails().getClientSecret());
    // 发起刷新请求
    GoogleTokenResponse googleTokenResponse = googleRefreshTokenRequest.execute();
    if (googleTokenResponse != null && StringUtils.isNotBlank(googleTokenResponse.getAccessToken())) {
        token = googleTokenResponse.getAccessToken();
    }
    return null;
}

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Google登录授权详细过程 的相关文章

  • 如何将未知列数的 ResultSet 映射到 List 并将其显示在 HTML 表中?

    我使用 Netbeans GlassFish 和 JavaDB 创建了一个数据库应用程序 现在我的控制器 Servlet 代码执行一些动态 SQL 查询并返回结果集 或者我可以更改 toString 现在 如何以表格格式显示返回的结果集 我
  • 单元测试组合服务方法

    我正在为一个类编写 junit 单元测试 该类使用以下方法实现公开的接口 public Set
  • Quarkus 不以编程方式选择 bean

    我试图以编程方式选择 bean 但 quarkus 不会注入 bean 并引发异常 不支持吗 public enum ReportType ONE TWO Qualifier Retention RUNTIME Target METHOD
  • 如何在log4j的配置文件中为文件附加器提供环境变量路径

    我有一个log4j xml配置文件 和一个RollingFileAppender我需要提供用于存储日志的文件路径 问题是我的代码将作为可运行的 jar 部署在 Unix 机器上 所以如果我传递这样的参数 value logs message
  • 如何在Java中优雅地处理SIGKILL信号

    当程序收到终止信号时如何处理清理 例如 我连接到一个应用程序 希望任何第三方应用程序 我的应用程序 发送finish注销时的命令 发送该信息最好说什么finish当我的应用程序被破坏时的命令kill 9 编辑1 kill 9无法被捕获 谢谢
  • 在 Java 中从 SOAPMessage 获取原始 XML

    我已经在 J AX WS 中设置了 SOAP WebServiceProvider 但我无法弄清楚如何从 SOAPMessage 或任何 Node 对象获取原始 XML 下面是我现在获得的代码示例 以及我试图获取 XML 的位置 WebSe
  • JTextField 和 JTextArea

    JTextField 和 JTextArea 有什么不同 是否可以在一个班级中使用这两个班级 总之 JTextField 是单行文本字段 而 JTextArea 可以跨越多行 文档中清楚地解释了这些差异 文本区 http docs orac
  • 具有 CRUD 功能的基于 Spring Web 的管理工具

    在 PHP Symfony 世界里有一个工具叫 Sonata Adminhttps sonata project org https sonata project org 基于 AdminLTE 模板 这是一款一体化管理工具 具有登录 菜单
  • 使用 JAX-WS 的 WebLogic 中没有模式导入的单个 WSDL

    如何使用 JAX WS 配置由 WebLogic 10 3 6 生成的 Web 服务 以将对象架构包含在单个 WSDL 文件声明 而不是导入声明 中 示例代码 界面 import javax ejb Local Local public i
  • 在 Junit 测试中使用 ReflectionTestUtils.setField()

    我是 JUnittesting 的新手 所以我有一个问题 谁能告诉我为什么我们使用ReflectionTestUtils setField 在我们的 Junit 测试示例中 正如评论中提到的 java 文档很好地解释了用法 但我还想给你们举
  • Java - JPanel 内有边距和 JTextArea

    我想创建这样的东西 主面板有其边距 x 并且 TextArea 位于该面板的中心 几乎填满了面板 底部是另一个具有自定义尺寸 高度 y 的面板 可以使用某些快捷方式将其切换为可见和不可见 底部面板有 FlowLayout 和几个元素 问题是
  • LocalDate 减去 period 得到错误的结果

    LocalDate减去一个Period 如 28年1个月27天 得到错误的结果 但减去一个Period 只有天单位 如 10282 天 得到正确的结果 有什么需要注意的吗 public static void main String arg
  • MongoDB java 驱动程序 3.0 在身份验证时无法捕获异常

    我超级卡住o 0 在尝试通过 Java 驱动程序进行身份验证时 存在捕获异常的问题 正如你可能会看到的Throwable类不工作 private MongoClient mongoClient private MongoDatabase m
  • 使用 HTTPServletRequestWrapper 包装请求参数

    我有一个可以验证 授权 REST 调用的过滤器 该过滤器需要访问请求参数 因此我为此编写了一个自定义 HTTPServletRequestWrapper import java util Collections import java ut
  • 配置jmxremote时无法正常停止tomcat

    我添加了一个jmxremotecatalina bat中的配置 set JAVA OPTS Dcom sun management jmxremote port 9004 Dcom sun management jmxremote ssl
  • JAXB 编组器无参数默认构造函数

    我想从 java 库中编组一个 java 对象 当使用 JAXB marschaller 编组 java 对象时 我遇到了一个问题 A 类没有无参数默认构造函数 我使用Java Decompiler来检查类的实现 它是这样的 public
  • Java8:流映射同一流中的两个属性

    我有课Model带有以下签名 class Model private String stringA private String stringB public Model String stringA String stringB this
  • Java和手动执行finalize

    如果我打电话finalize 在我的程序代码中的一个对象上 JVM当垃圾收集器处理这个对象时仍然再次运行该方法吗 这是一个大概的例子 MyObject m new MyObject m finalize m null System gc 是
  • Java 中处理异步响应的设计模式

    我读过类似问答的答案 如何在 JAVA 中创建异步 HTTP 请求 https stackoverflow com questions 3142915 how do you create an asynchronous http reque
  • CXF:通过 SOAP 发送对象时如何排除某些属性?

    我使用 Apache CXF 2 4 2 当我将数据库中的某个对象返回给用户时 我想排除一些属性 例如密码 我怎样才能做到这一点无需创建临时的班级 有这方面的注释吗 根据 tomasz nurkiewicz 评论我应该使用 XmlTrans

随机推荐

  • np.dot(a, b)用法

    In short np dot a b 就是一个乘法函数 数和数相乘 若a和b都是数 np dot 1 2 2 一维数组的内积 np dot 1 2 3 4 5 6 1 2 3 4 5 6 1x4 2x5 3x6 32 矩阵的乘积 x np
  • Unity学习笔记——TextMeshPro使用详解

    https blog csdn net elineSea article details 88799896 TextMesh Pro是Unity默认文本组件的替代品 TextMesh Pro和默认组件一样拥有高性能 它使用了完全不同的Sig
  • 为什么大部分人认为测试用例不重要?如何正确编写软件测试用例?

    如何编写测试用例似乎不是开发的重要部分 但是为了让一个软件测试人员最好地完成他们的工如如何编写测试用例似乎不是开发的重要部分 但是为了让一个软件测试人员最好地完成他们的作 他们需要一套清晰的步骤和一个被测试的东西的清晰定义 编写优秀的测试用
  • 代码审查常见代码质量问题

    配套的Bug解释模式 为了有针对性的使用这个工具 减少bug的误报 提高使用效率 我们选择了10个左右的bug模式 下面就是对这10个模式的解释 这些bug可能会引起程序的性能或逻辑问题 需要说明的是 findbugs能检测的bug pat
  • 有哪些好用的设计图工具?

    设计图纸制作软件是高级学习数字设计的最佳选择 无论你是想通过设计图纸制作软件创建一个明亮的设计 还是与其他设计师分享和交流 本文将介绍十个易于使用的设计图纸制作软件 其中大多数是初学者和高级艺术家 具有完整的绘图 照片编辑和小图形设计项目功
  • jmeter 安装_JMeter安装教程

    一 安装JMeter之前我们需要下载Java的jdk Java软件开发工具包 这是因为JMeter软件是由Java代码100 开发的 Java代码要运行必须依托于JVM Java虚拟机 因此JMeter如果要运行也必须要在有JVM环境的系统
  • STM32学习记录 中断

    STM32 中断非常强大 每个外设都可以产生中断 中断类型有 系统异常 外部中断 NVIC 嵌套向量中断控制器 属于内核外设 管理着包括内核和片上所有外设的中断相关的功能 两个重要的库文件 core cm3 h和misc h 中断编程的顺序
  • C语言文件操作详解

    目录 前言 一 文本数据和二进制数据 文本数据 二进制数据 文本文件和二进制文件 二 文件的打开和关闭 文件指针 打开文件 小细节 关闭文件 举个例子 注意事项 三 文本文件的读写 向文件中写入数据 举个例子 运行效果 从文件中读取数据 举
  • 什么是黑盒测试,和白盒测试的区别有哪些?

    软件测试是软件工程中的一个非常重要的环节 是开发项目整体的一部分 是伴随软件工程的诞生而诞生的 但软件测试不是万能的 不可能发现全部缺陷 其中 黑盒测试和白盒测试是两种不同类型的软件测试策略 它们具有同样强大的功能 白盒测试和黑盒测试往往不
  • 浅谈Android版本更新

    关于本文DownloadManager版本更新的源码链接详见我的开源项目AppUpdate 前言 版本升级对于app来讲已经是非常常见的功能了 每次项目的版本迭代 新功能的开发都需要下载更新新版本 通过安装新版本来实现我们的迭代 当然除了这
  • 图解Redis中的9种数据结构

    如图所示 Redis中提供了9种不同的数据操作类型 他们分别代表了不同的数据存储结构 图2 17 数据类型 String类型 String类型是Redis用的较多的一个基本类型 也是最简单的一种类型 它和我们在Java中使用的字符类型什么太
  • Quartz学习总结之核心接口Scheduler、Job

    参考文章 https www cnblogs com mengrennwpu p 7141986 html 核心接口如下 接口 含义 Scheduler scheduler的主要API接口 Job 任务实现接口 期望调度器能够执行 JobD
  • c++ oop构造函数与拷贝控制

    class Quote public Quote int x x x 如果我们删除的是一个指向派生类对象的基类指针 则需要虚析构函数 virtual Quote default 动态绑定析构函数 int x virtual void sho
  • [YOLO专题-18]:YOLO V5 - ultralytics代码解析-总体架构

    作者主页 文火冰糖的硅基工坊 文火冰糖 王文兵 的博客 文火冰糖的硅基工坊 CSDN博客 本文网址 https blog csdn net HiWangWenBing article details 122356975 目录 第1章 YOL
  • 多线程进阶

    同步与互斥 什么是同步 有序性 完整性 原子性 什么是互斥 什么是临界区 可以限制线程并发访问共享资源 达到同步与互斥目的的程序片段 阻隔线程 排斥线程 同步代码块 格式示例 使用说明 同步方法 使用格式 使用解释 示例代码 释放同步监视器
  • 03C++11多线程编程之测试join,detach传各种实参时形参的拷贝次数

    03C 11多线程编程之测试join detach传各种实参时形参的拷贝次数 首先我们看下面的总结测试图 然后一步步的测试 1 这里我们先测试join传实参的类型 当实参为普通对象时 1 当形参为普通对象时 拷贝了两次 2 当形参为引用时
  • 计算机二级python(本人整理的所有含答案操作题)

    全国计算机二级 本人整理的所有操作题 包括答案 直接上链接 有道云笔记 喜欢的可以直接下载 本人复习了三天 看了视频 把所有解题记了一遍 直接过了 https note youdao com ynoteshare index html id
  • 机器学习常识 17: 多标签学习

    摘要 多标签学习从标签个数上来扩展数据模型 进一步还有标签分布学习 1 基本概念 多标签学习在 机器学习常识 3 分类 回归 聚类 中简单提到过 这里列举出几个相关概念 一起来讨论下 将训练数据的标签表示为 Y mathbf Y Y 二分类
  • idea搜索不到free mybatis plugins

    作者Gitee主页说明 换行业 不再维护 Jb market也提交了下架 下面有一个peer move and update插件 地址是 https github com chuntungho free mybatis plugins 或者
  • Google登录授权详细过程

    前言 这篇文章包含了google登录授权从API创建 到使用Java代码完成登录的一个完整demo 主要为了实现google关联用户的服务 如google merchant center等 如果仅仅需要使用google邮箱登录 建议由前端实