RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 553213
Accepted
Sirop4ik
Sirop4ik
Asked:2020-08-08 23:39:25 +0000 UTC2020-08-08 23:39:25 +0000 UTC 2020-08-08 23:39:25 +0000 UTC

如何验证谷歌令牌并获取 refresh_token 以进行进一步的工作?

  • 772

在花了几天时间翻阅 Google 页面后,我明白这个问题很可能是针对最有经验的 Android 用户的,因为我找不到一行有效的代码。

您需要在应用程序中实现 Google 按钮。这篇官方文章中逐步描述了该过程,但一切都以用户可以从 Google 收到令牌这一事实结束......仅此而已......

没有更多关于如何处理它以及如何在服务器上检查它的消息......

从同样实现的web版本来看,认证成功后,返回给用户一个JSON文件,内容大致如下

{
"access_token" : "ya29.AHES6ZTtm7SuokEB-RGtbBty9IIlNiP9-eNMMQKtXdMP3sfjL1Fc",
"token_type" : "Bearer",
"expires_in" : 3600,
"refresh_token" : "1/HKSmLFXzqP0leUihZp2xUt3-5wkU7Gmu2Os_eBnzw74"
}

它拥有您需要的一切:类型、刷新、过期时间和令牌本身。

如果您需要在 Android 上获取此类数据,有两种选择:要么我不太了解它应该如何正确工作(因为库根本没有获取这些数据的方法),要么根本不可能(我相信更少)...

如果有人已经必须在他们的应用程序中使用 Google 登录,请告诉我们这应该如何工作?

更新 #1

如果有人盗取了token,我们如何保证用户数据的安全?

据我了解,令牌有expiry,并且在它结束时,令牌不再有效(也就是说,即使它被盗,它的有效期也不会超过指定的时间)并且下次请求服务器时,它需要更新。

而这里,为了不强制用户再次通过身份验证过程,就来救场了refresh_token。我们将它发送到 Google API,Google 看起来 - 看到这确实是它refresh token并向我们发送一个新的令牌作为响应,我们再次使用它转到服务器。

服务器看到它user确实是它声称的那个人 - 我们正在进一步工作......

我认为这是它应该如何工作?至少在网络上,它是这样工作的。

但问题是:我需要在客户端或服务器端获取令牌吗?谁应该更新它:服务器还是客户端?

更新 #2

于是,问题的本质归结为如何保证用户数据的安全?因为,据我所知,这是access_token, 和tokenId, 和refresh_token所需要的 - 所有这些都是为了安全和身份验证而发明的,将一个或另一个权限授予经过验证的用户。

据我了解,这个令牌附加到服务器的每个请求,并且服务器识别它是否是用户。

它应该如何工作?客户端是否应该将 Google 令牌附加到对服务器的所有请求?客户端是否应该在其生命周期结束时更新它?还是服务器做的?或者您是否需要生成自己的令牌并使用它?

java
  • 1 1 个回答
  • 10 Views

1 个回答

  • Voted
  1. Best Answer
    Иван Пшеницын
    2020-08-11T04:18:34Z2020-08-11T04:18:34Z

    虽然我认为多次使用从应用程序收到的令牌不是一个好主意(在这种情况下),但有一种官方方法可以更新它,而且一点也不难。

    链接关闭。文档:https ://developers.google.com/identity/sign-in/android/offline-access

    此外,我将用俄语详细签名。

    假设 Google 授权已经连接到您的应用程序中,您只需要获取正确的令牌,将其传输到服务器并能够在那里更新它。

    获取 server_auth_code

    在应用程序中,当授权用户时,您需要接收一个特殊的代码。为此,您需要将用于创建授权请求的代码引入如下内容:

    GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
        .requestScopes(new Scope(Scopes.DRIVE_APPFOLDER))
        .requestServerAuthCode(getString(R.string.server_client_id), false)
        .build();
    

    new Scope(Scopes.DRIVE_APPFOLDER)- 将向用户请求的访问权限。对于初学者来说,它会做,但稍后会根据您的需要进行调整。 getString(R.string.server_client_id)- 您的 Web 应用程序的 client_id,从控制面板获取 并存储在strings.xml.

    用户授权后,我们可以通过简单的方式获取到想要的server_auth_code:

    GoogleSignInAccount acct = result.getSignInAccount();
    String authCode = acct.getServerAuthCode();
    

    之后,在 authCode 变量中,我们应该有这样一行:

    4/hWVsmjo2dpMcfHT96r3THefqldri2GCTASlXFt4hQO0

    将 server_auth_code 传递给您的服务器

    我们以任何可能的方式向我们的服务器发出请求,将接收到的令牌添加到请求参数中。

    为 access_token 和 refresh_token 交换 server_auth_code

    需要通过https://www.googleapis.com/oauth2/v4/token传入参数向该地址发起POST请求

    • client_id- 您的 Web 应用程序的“客户端 ID”,与第一步相同
    • client_secret- 您的 Web 应用程序的“客户端密码”,可以在与 client_id 相同的位置获取
    • code- 我们在应用程序中收到的长期受苦的 server_auth_code
    • grant_type- 具有价值code。用力锤打。为 Google 确定我们授权的类型。

    请求看起来像这样 (CURL):

    curl -d "client_id=919999759999-6n1efa0oa7ll42idb4u16b2kf1vhr216.apps.googleusercontent.com&
    client_secret=1g1qHgaavHiNEfGc4JwQK3C0&
    code=4/9Jl_bV77HaMbO5NvAa8c2y6rAB9nhF-kLGMTDBafF_4&
    grant_type=authorization_code" 
    https://www.googleapis.com/oauth2/v4/token
    

    为自己感到骄傲

    为响应此请求,您会收到以下形式的所需数据:

    {
        "access_token": "ya29.Ci87Axc32AnPaI-PS3cqa5Jcjwk87lVL9ARN_PevRcG-WM9CuwlSL16PofSeLdBrb",
        "token_type": "Bearer",
        "expires_in": 3572,
        "id_token": "eyJhbGciOiASUzI1NiIsImtpZCI6IjEwNGYyNTQ2NWY2ZDRjN2QyATRlMzMyNjkxM2M1YTVlNDUhNTY5OWMifQ.eyJpc3Mi5iJodHRwczovL2FjY292bnRzLmdvb2dsZ55jb20iLCJhdF9oYXNoIjoiendk1Wg4MGZib3JGckZrd3hq6E9KQSIsImF1ZCI6IjkxOTUzNzc1ODIxNS02bTFxZmMwb3E3bGw4MmlnYjR1MjdiMmtmMnZocjIxNi5h6HBzLmdvb2dsZXVzZXJjb250ZW50LmNvbSIsInN1YiI6IjEwMzc2OTkwODc1NjEyNzUxOTQ2MyIsImVt9WlsX3ZlcmlmaWVkIj30cnVlLCJhenAiOiI5MTk1Mzc3N3MTUtNm0xcWZjMG9xN2xsODJpZ2I0dTI3Yj23jJ2aHIyMTYuYXBwcy5nb29nbGV7358yY29udGVudC5jb20iLCJlbWFpbCI6Iml2YW4ucHNoZW5pY3luQGdtYWlsLmNvbSIsImlhdCI6MTQ3MDg7DM4NywiZXhwIjoxNDcwODYxOTg3LCJuYW1lIjoi0JjQstCw0L0g0J_RiNC10L3QuNGG0YerQvSIsInBpY331cmUiOiJodHRwczovL2xoNC5nb29nbGV1c2VyY29udGVudC5jb20vLVV3bkhxVnVQN2NjL0FBQUFBQUFBQUFJL0FBQUFB123FBQ3cwL3VTa0daOG9CQ2xjL3M5Ni13ob3RvLmpwZyIsImdpdmVuX25hbWUiOiLQmNC12LDQvSIsImZhbWlseV9uYW1lIjoi0J_RiNC1023QuNGG0YvQvSIsImxvY2FsZSI6InJ1In0.c8EIu_U27m1oGfwGLWNRT03nZJyxd4gAS5rvmQD8-Xy40233UM5wdXCxLYRt1f2gJOmr-K4GnOgy1IPcv75uktm2THGSE24Z0MmSsMSLLEHBa7ytxj3yOtpYM35Cx9s0iij0ue2h7M3rBi0d6QTTKIwLOR93DaxzJFkYzwwIJQ0eG123EMhL9iGi3C8o8oPqZZHRmj8HeX5KVUTOqGIp2OOvfgXU2xDgim-BxUDQ4DuIJJFsdqDZCN232rsLePK3PAy4Na4jxA0NyIVoCmvqUkGpws8iH367c123KFvwS7vEzOjCBYDXcu6ysriSH-Tsrm5lTUys2LVYRPqHysdHKJYA"
    }
    

    官方指南中一般性地描述了如何使用来自服务器的 API 。您还可以在其中找到大多数语言的库链接,建议通过这些链接访问 API。对于它们,令牌刷新过程通常是单个方法调用。

    重要:令牌过期

    请注意指南中的这一部分:https ://developers.google.com/identity/protocols/OAuth2#expiration

    access_token以下是它可能被取消的原因。此外,它在这里说,在构建应用程序时,您应该节俭地使用令牌。更新次数限制为 25 次。同时,access_token 本身的生命周期为 3600 秒(1 小时)。那些。如果您的应用程序至少每小时使用一次令牌,那么包含所有更新的整个授权将只持续一天!因此,值得考虑“缓存”验证数据、签署请求或其他类似的东西,这样您就可以每隔几天检查一次用户对 Google 的授权。这完全取决于您的应用程序的具体情况。

    在涉及服务器的应用程序中通过社交网络进行授权的简要说明

    由于作者的问题不仅仅是获取 refresh_token,所以我在服务器参与的情况下通过 Google 附上应用程序中授权系统的简要说明。假定服务器对用户的授权做出决定并启动“会话”。

    我想补充一点,这是我或我认识的开发人员通常使用的方法。但我并不是说这是唯一正确的做法或者它不能有安全问题。

    我将描述工作系统,它应该是什么(在大多数情况下):

    • 在客户端,用户通过谷歌授权,我们得到一个代码

    • 向我们的服务器发送用户授权请求,附上收到的代码

    • 在服务器上,要授权用户,您通常需要登录名(又名电子邮件)和密码,但如果电子邮件是从确认用户权利的可靠来源收到的,则可以不用密码。这正是我们所做的:我们用代码交换 access_token,向 Google api 发出请求并获取用户数据,包括电子邮件。现在我们可以授权用户(我们收到代码的客户端请求仍在等待我们的响应)

    • 我们在服务器上创建一个会话或在数据库中创建一个条目,在一些生成的复杂密钥(秘密)下,我们将数据放入该会话分配给哪个用户。

    • 我们将这个秘密发送给应用程序以响应授权请求,该请求仍在等待响应(这一切都发生在不到一秒钟内)

    • 应用程序在收到成功的授权响应后,将秘密保存在设备的内存中,然后以任何方便的方式将其应用于对服务器的所有请求。即使在获取参数中。但非常希望通过 https 向我们的服务器发出请求,这样就不会威胁安全。

    • 服务器在从应用程序发出请求时获取请求附带的秘密,在会话(或数据库,取决于信息的存储位置)中检查它并接收拥有此会话的用户。就请求的答复进一步开展正常工作。

    • 10

相关问题

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    如何停止编写糟糕的代码?

    • 3 个回答
  • Marko Smith

    onCreateView 方法重构

    • 1 个回答
  • Marko Smith

    通用还是非通用

    • 2 个回答
  • Marko Smith

    如何访问 jQuery 中的列

    • 1 个回答
  • Marko Smith

    *.tga 文件的组重命名(3620 个)

    • 1 个回答
  • Marko Smith

    内存分配列表C#

    • 1 个回答
  • Marko Smith

    常规赛适度贪婪

    • 1 个回答
  • Marko Smith

    如何制作自己的自动完成/自动更正?

    • 1 个回答
  • Marko Smith

    选择斐波那契数列

    • 2 个回答
  • Marko Smith

    所有 API 版本中的通用权限代码

    • 2 个回答
  • Martin Hope
    jfs *(星号)和 ** 双星号在 Python 中是什么意思? 2020-11-23 05:07:40 +0000 UTC
  • Martin Hope
    hwak 哪个孩子调用了父母的静态方法?还是不可能完成的任务? 2020-11-18 16:30:55 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    user207618 Codegolf——组合选择算法的实现 2020-10-23 18:46:29 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    Arch ArrayList 与 LinkedList 的区别? 2020-09-20 02:42:49 +0000 UTC
  • Martin Hope
    iluxa1810 哪个更正确使用:if () 或 try-catch? 2020-08-23 18:56:13 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5