Google :: Apis :: AuthorizationError(未经授权)

时间:2018-05-25 06:46:36

标签: ruby-on-rails google-oauth gmail-api google-client

我们正在创建一个以Ionic框架作为前端和Ruby on Rails作为后端的应用程序。我们可以在我们的应用中关联Gmail帐户。帐户关联工作正常,我们从前端获取 serverAuthCode ,然后使用我们获取刷新令牌,我们可以在第一次尝试时使用该刷新令牌获取电子邮件。但在几秒钟内,它就会过期或被撤销。得到以下问题:

Signet::AuthorizationError (Authorization failed.  Server message:
{
  "error" : "invalid_grant",
  "error_description" : "Token has been expired or revoked."
})

看来,刷新令牌本身就会在几秒钟内到期。有没有人知道如何解决它?

更新

现有代码如下所示:

class User   
  def authentication(linked_account)
    client = Signet::OAuth2::Client.new(
    authorization_uri: 'https://accounts.google.com/o/oauth2/auth',
    token_credential_uri: Rails.application.secrets.token_credential_uri,
    client_id: Rails.application.secrets.google_client_id,
    client_secret: Rails.application.secrets.google_client_secret,
    scope: 'https://www.googleapis.com/auth/gmail.readonly, https://www.googleapis.com/auth/userinfo.email, https://www.googleapis.com/auth/userinfo.profile',
    redirect_uri: Rails.application.secrets.redirect_uri,
    refresh_token: linked_account[:refresh_token]
  )

  client.update!(access_token: linked_account.token, expires_at: linked_account.expires_at)
  return  AccessToken.new(linked_account.token) unless client.expired?
  auth.fetch_access_token! 
 end

 def get_email(linked_account)
   auth = authentication(linked_account)
   gmail = Google::Apis::GmailV1::GmailService.new
   gmail.client_options.application_name = User::APPLICATION_NAME
   gmail.authorization = AccessToken.new(linked_account.token)
   query = "(is:inbox OR is:sent)"
   gmail.list_user_messages(linked_account[:uid], q: "#{query}")
   ## Getting error over here ^^
  end
end // class end 

class AccessToken
  attr_reader :token
  def initialize(token)
    @token = token
  end

  def apply!(headers)
    headers['Authorization'] = "Bearer #{@token}"
  end
end

参考链接:https://github.com/google/google-api-ruby-client/issues/296

6 个答案:

答案 0 :(得分:0)

refresh token永不过期的想法实际上是一种误解。实际场景是服务器发出短期访问令牌和长期刷新令牌。所以实际上发生的事情是访问令牌可以使用长期刷新令牌重新获得但是,你必须请求一个新的刷新令牌(因为它也会过期!)。例如;您可以将刷新令牌视为永不过期。但是,在登录检查新用户时,如果用户撤消刷新令牌,在这种情况下,Google会在登录时提供新的刷新令牌,因此只需更新刷新令牌。

现在条件可能是用户撤消对您的应用程序的访问权限。在这种情况下,refresh token将过期(或者我应该说它将成为未经授权的人)。因此,如果这是您的情况,您将不得不考虑避免撤消对应用程序的访问。

为了更好地理解它,您可以参考此document甚至OAuth 2.0 documentation

答案 1 :(得分:0)

据我所知,问题似乎出现在这两条线上。正在检查令牌到期的方式并生成新令牌。如果可重现的代码很少,那就太棒了。

return  AccessToken.new(linked_account.token) unless client.expired?
auth.fetch_access_token! 

以下是我获取访问令牌的方法:

  def self.access_token(refresh_token)
    Cache.fetch(refresh_token, expires_in: 60.minutes) do
      url = GoogleService::TOKEN_CREDENTIAL_URI
      # p.s. TOKEN_CREDENTIAL_URI = 'https://www.googleapis.com/oauth2/v4/token'
      _, response = Request.post(
        url,
        payload: {
          "client_id": GoogleService::CLIENT_ID,
          "client_secret": GoogleService::CLIENT_SECRET,
          "refresh_token": refresh_token,
          "grant_type": "refresh_token"
        }
      )
      response['access_token']
    end
  end

然后将此访问令牌用于任何目的。让我知道它是如何发生的,如果你能够创建一个可重现的API版本。那将是伟大的。

答案 2 :(得分:0)

刷新令牌停止工作的原因有多种。

  1. 如果不使用,它会在六个月后过期。#/ li>
  2. 用户可以重新刷新您的应用程序并获得一个新的刷新令牌,刷新令牌将起作用,您可以拥有最多五十个未完成的刷新令牌,然后第一个将停止工作。
  3. 用户可以撤消您的访问权限。
  4. 2015年Wakey夏令时错误。(我们不会谈论那个)
  5. Gmail并重置密码。

    这主要是因为密码重置。当用户更改密码时,将撤消使用gmail范围的OAuth授权。

    请参阅Automatic OAuth 2.0 token revocation upon password change

    通常,用户可以随时撤销拨款。您应该能够优雅地处理该情况并提醒用户,如果他们希望继续使用所提供的功能,则需要重新授权。

    您一直在进行大量测试我猜您是否在保存最新的刷新令牌?如果没有,那么你可能正在使用旧的刷新令牌,它将停止工作。 (2号)

答案 3 :(得分:0)

您是否尝试使用刷新令牌刷新访问令牌?您可以捕获错误并重试。

这样的事情:

begin
  gmail.list_user_messages(linked_account[:uid], q: "#{query}")
rescue Google::Apis::AuthorizationError => exception
  client.refresh!
  retry
end

答案 4 :(得分:0)

发布的代码不足,但发布的内容看起来不对。

  • linked_account未定义
  • 无处显示linked_account.token已更新(或已设置)。当refresh_token用于获取新的访问令牌时,需要更新它。
  • auth似乎未在行auth.fetch_access_token!
  • 中定义
  • GmailService#authorization=需要Signet::OAuth2::Client而不是AccessToken

可能发生的事情是,您在linked_account.token中拥有有效的访问令牌,直到您拨打client.update!,这会获取新的访问令牌并使旧令牌无效。但是,由于您永远不会更新linked_account,因此在您通过重置代码路径之前,将来的调用将失败。

如果访问令牌已过期,您只需要调用client.update!,如果访问令牌已过期而您获得新的令牌,则需要将该新令牌存储在linked_account.token中。

答案 5 :(得分:0)

就我而言,只有youtube 上传 api提升

Unauthorized (Google::Apis::AuthorizationError)

和其他api(例如列表视频api)效果很好

这是因为我使用了新的Google帐户并且没有注册视频

我在youtube网络中手动上传视频,youtube要求我创建“频道”

然后我再次尝试youtube up API,

我想这是因为youtube拥有了向上频道