【问题标题】:Problem accessing Google API protected with OAuth2 by using LWP::Authen::OAuth2使用 LWP::Authen::OAuth2 访问受 OAuth2 保护的 Google API 时出现问题
【发布时间】:2019-04-01 13:10:26
【问题描述】:

我目前正在 perl 服务器上编写一个服务,该服务将向 Firebase Cloud Messaging API 发送一个请求,该 API 然后将推送通知发送到一个应用实例。

由于 FCM 是 Google API 系列的一部分,因此需要 OAuth2 令牌才能访问 API。在我的研究中,我发现了this perl 解决方案。因为我的服务是在非谷歌服务器环境中运行的,所以我不能使用谷歌应用默认凭据,而是必须手动提供,所以我下载了一个 json,其中包含this 描述后面的私钥。

阅读documentation of LWP::Authen::OAuth2 我有点困惑,将json中的哪个参数放入$oauth2对象中,因为通常使用不同的名称来引用相同的值,就像我怀疑的那样。

与我的firebase项目相关的json:

{
    "type": "service_account",
    "project_id": "my_project_id",
    "private_key_id": "some_key_id",
    "private_key": "-----BEGIN PRIVATE KEY-----very_long_key-----END PRIVATE KEY-----\n",
    "client_email": "firebase-adminsdk-o8sf4@<my_project_id>.iam.gserviceaccount.com",
    "client_id": "some_client_id",
    "auth_uri": "https://accounts.google.com/o/oauth2/auth",
    "token_uri": "https://oauth2.googleapis.com/token",
    "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
    "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-o8sf4%40<my_project_id>.iam.gserviceaccount.com"
}

$oauth 对象的实现如下所示:

my $oauth2 = LWP::Authen::OAuth2->new(
             client_id => "Public from service provider",
             #probably that will be "some_client_id" from above

             client_secret => "s3cr3t fr0m svc prov",
             #the "very_long_key"?

             service_provider => "Google",
             #the "auth_uri"? That's what I would suggest here
             #I've read some about the LWP::Authen::OAuth2::ServiceProvider module 
             #do I have to create an instance of that here?
             #if so, which params do I need for that from the json?

             redirect_uri => "https://your.url.com/",
             #the FCM api I want to call?

             # Optional hook, but recommended.
             save_tokens => \&save_tokens,
             save_tokens_args => [ $dbh ],

             # This is for when you have tokens from last time.
             token_string => $token_string.

             #yes, i copy-pasted that from the docs
         );

现在,作为 Perl 的初学者和不喜欢模棱两可的键值名称的人,我有点困惑,将哪个值放在哪里,如果有人可以在这里为我提供指导,我会很高兴,把什么放在哪里即使这似乎是一个非常菜鸟的问题,这对我来说很重要:D。所以我很感谢每一个有用的答案!

编辑

当尝试使用 Crypt::JWT 在我的 perl 服务中手动生成 JSON Web 令牌 时,我遇到了另一个绊脚石,这让我怀疑来自 Google "https://www.googleapis.com/auth/firebase.messaging" 的相应身份验证 API 仍然接受不记名令牌...我尝试生成我的 JWT,这似乎是成功的,但是我发送到实际 FCM API 的请求然后给了我这个:

Request had invalid authentication credentials. 
Expected OAuth 2 access token, login cookie 
or other valid authentication credential

在打印为字符串的响应中,我发现了这个小家伙,这让我很困惑:

Client-Warning: Unsupported authentication scheme 'bearer'

现在我非常不确定,FCM API 仍然支持不记名令牌,即使它们在引用 docs page 的示例中使用。有没有人有这方面的最新信息?非常感谢!

【问题讨论】:

  • 太棒了,因为我被一只美丽的独角兽分心了,很多闪光我忘了添加所有链接...稍后会跟进:D - 添加链接
  • 我稍微分解了我的不记名令牌问题,以保持问题的可读长度。要获取更多详细信息和代码 sn-ps,请参阅此问题:stackoverflow.com/questions/55494788/…

标签: perl oauth-2.0 google-api firebase-cloud-messaging lwp


【解决方案1】:

深入研究各种文档并测试我意识到的一些事情,LWP::Authen::OAuth2 不仅有点开销,对于创建一个非常小的 HTTPS 请求到受 OAuth2 保护的 API,目前也不可能.

警告隐藏在托管身份验证 API 的 service_provider 中,我必须调用它来验证和授权我的服务以访问实际的 Firecase 云消息传递 API。就我而言,这是 Google,更准确地说是 https://www.googleapis.com/auth/firebase.messaging,在代码中也称为 scope

现在一个服务提供商可以为不同的客户端提供不同的身份验证 API。这就是为什么一些服务提供商需要一个额外的参数——分别是client_typetype(为了清楚起见,我将使用client_type)——这也会影响通过 OAuth2 进行的身份验证和授权过程。

当创建一个新的$oauth2-object,并为字段service_provider赋值时,模块LWP::Authen::OAuth2::ServiceProvider的一个对象被创建,可能还需要它的参数,比如scope,来定义,您希望获得哪个 API 系列的授权,具体取决于 client_type

现在 Google 不是无名服务提供商,因此已经有一个预构建的 ServiceProvider 模块,专门用于 Google API:LWP::Authen::OAuth2::ServiceProvider::Google。这会自动填充ServiceProvider 对象的一些参数,并保存可用client_types 的散列以确保您使用其中一个,因为根据client_typeServiceProvider::Google 的特定子模块会在内部创建.

所以我尝试这样测试:

my $oauth2 = LWP::Authen::OAuth2->new(
    service_provider => "Google",
    scope => "https://www.googleapis.com/auth/firebase.messaging", 
    client_type => "service_account", #referring to 'type' in the json 
    client_id => "Public from service provider",
    client_secret => "s3cr3t fr0m svc prov",
    redirect_uri => "this-server.mydomain.com"
);

按照here 的进一步描述并使用内置的 LWP::UserAgent 对象发送请求,我仍然收到 401 错误UNAUTHENTICATED,这让我很困惑。因此,当我阅读文档时,我不知道是什么时候在ServiceProvider::Googleclient_types 章节中跨过这条细线:

服务帐号

此 client_type 适用于使用开发人员凭据登录到开发人员帐户的应用程序。有关 Google 的文档,请参阅 https://developers.google.com/accounts/docs/OAuth2ServiceAccount

目前尚不支持,需要使用 JSON Web Tokens 来支持。

是的,这有点破坏了整个 LWP:Authen::OAuth 系列访问 Firebase API 的使用,因为几乎所有这些 API 都有 client_type =&gt; "service_account"。现在我的项目有一个截止日期,我迫不及待地想要扩展模块,否则我自己扩展它会超出我的 perl 技能。

但在绝望的泪水之间总有一丝希望,正如我发现 this Google 文档页面有一个拯救生命的附录,可以使用 JSON Web Token 作为不记名令牌。为此,我发现不止一个 Perl 解决方案可以像服务帐户一样从 JSON 生成 JWT,还有 this 非常有用的 Stackoverflow 答案,它向我展示了摆脱瓶颈的方法。

【讨论】:

  • 即使我不会继续上面的方法,如果您知道使用 LWP::Authen::OAuth 访问 FIrebase API 的方法,请随时分享您的宝贵知识。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-25
  • 2018-06-13
  • 2018-05-26
  • 2015-06-05
  • 2013-12-18
  • 2013-03-19
相关资源
最近更新 更多