4

我的omniauth 应用程序的行为很奇怪。基本上,我有管理面板,需要访问它才能使用 Yandex 帐户进行身份验证。

问题:我按照多个指南的要求进行了所有操作,并且从昨天开始我尝试使用 Yandex 帐户进行身份验证并收到 HTTPBadRequest 错误,一切正常。

注意:我的代码没有改变一点。我所有的访问数据 client_Id 和密码也没有改变。

宝石文件:

gem "omniauth-yandex"

路线:

devise_for :users, :controllers => { :omniauth_callbacks => "callbacks" }

回调控制器:

def yandex
    require 'net/http'
    require 'json'  # => false

    @user = User.from_omniauth(request.env["omniauth.auth"])

    @client_id = Rails.application.secrets.client_id 
    @secret =  Rails.application.secrets.password
    @authorization_code = params[:code]

    @user.update_attribute(:code, @authorization_code)
    @user.update_attribute(:state, params[:state])


    @post_body = "grant_type=authorization_code&code=#{@authorization_code}&client_id=#{@client_id}&client_secret=#{@secret}"

    @url = "https://oauth.yandex.ru/token"

    url = URI.parse(@url)
    req = Net::HTTP::Post.new(url.request_uri)
    req['host'] ="oauth.yandex.ru"
    req['Content-Length'] = @post_body.length
    req['Content-Type'] = 'application/x-www-form-urlencoded'
    req.body = @post_body
    http = Net::HTTP.new(url.host, url.port)
    http.use_ssl = (url.scheme == "https")

    @response_mess = http.request(req)

    refreshhash = JSON.parse(@response_mess.body)
    access_token  = refreshhash['access_token']
    refresh_token  = refreshhash['refresh_token']
    access_token_expires_at = DateTime.now + refreshhash["expires_in"].to_i.seconds


    if access_token.present? && refresh_token.present? && access_token_expires_at.present?
        @user.update_attribute(:access_token, access_token)
        @user.update_attribute(:refresh_token, refresh_token)
        @user.update_attribute(:expires_in, access_token_expires_at)

        sign_in(@user)
        redirect_to admin_dashboard_index_path
    end

end

用户型号:

    require 'rest-client'

      devise :database_authenticatable, :registerable,
          :recoverable, :rememberable, :trackable, :validatable,
          :omniauthable, :omniauth_providers => [:yandex]

      def self.from_omniauth(auth)
          where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
            user.provider = auth.provider
            user.uid = auth.uid
            user.email =  auth.info.email
            user.code = auth.info.code
            user.state = auth.info.state
            user.password = Devise.friendly_token[0,20]
          end
      end

      def refresh_token_if_expired
          if token_expired?
            response    = RestClient.post "https://oauth.yandex.com/token",
            :grant_type => 'refresh_token',
            :refresh_token => self.refresh_token

            refreshhash = JSON.parse(response.body)

            self.access_token     = refreshhash['access_token']
            self.expires_in = DateTime.now + refreshhash["expires_in"].to_i.seconds

            self.save

            puts 'Saved'
          end
      end

      def token_expired?          
          expiry = Time.at(self.expires_in)
          logger.debug "#{expiry}"
          return true if expiry < Time.now 
          token_expires_at = expiry
          save if changed?
          false 
      end
  end

问题

HTTPBadRequest错误突出显示以下行CallbacksController

@response_mess = http.request(req)

我尝试过的

1) 重启 Rails 应用程序;

2)从数据库中删除用户并尝试再次登录;

3) 在Yandex Oauth部分中删除了已注册的应用程序。然后使用新的 client_id 和密码再次添加回来。

来自 Yandex Oauth 指南

Exchanging an authorization code for a token

The application sends the code, along with its ID and password, in a POST request.
POST /token HTTP/1.1
Host: oauth.yandex.
Content-type: application/x-www-form-urlencoded
Content-Length: <length of request body>
[Authorization: Basic <encoded client_id:client_secret string>]

   grant_type=authorization_code
 & code=<authorization code>
[& client_id=<application ID>]
[& client_secret=<application password>]
[& device_id=<device ID>]
[& device_name=<device name>]

更新:我收到此错误:

{"error_description": "Code has expired", "error": "invalid_grant"}

更新 2:我尝试联系 Yandex 支持。我向他们发送了对我的问题的简要描述和问题的链接。但没有回应。

更新 3:

我在 CHROME POSTMAN 中尝试了相同的 POST 请求并收到了相同的响应

{"error_description": "代码已过期", "error": "invalid_grant"}

更新 4:

我再次检查了 Yandex 的所有凭据 client_id 和密码,它们 100% 有效。

4

1 回答 1

3

来自OAUTH 2.0 RFC

invalid_grant
    The provided authorization grant (e.g., authorization
    code, resource owner credentials) or refresh token is
    invalid, expired, revoked, does not match the redirection
    URI used in the authorization request, or was issued to
    another client.

这在Yandex 网站上有进一步的解释:

无法颁发 access_token。临时授权码不是由 Yandex.Money 颁发的,或者它已经过期,或者已经为此临时授权码颁发了 access_token(使用相同临时授权码的访问令牌的重复请求)。

您向 Yandex 提供了无效凭据。暂时忘记您编写的代码,因为唯一失败的部分是它将数据发送到 Yandex。Yandex 告诉您数据无效,您已向 Postman 确认了这一点。这意味着这是发送无效数据:

@post_body = "grant_type=authorization_code&code=#{@authorization_code}&client_id=#{@client_id}&client_secret=#{@secret}"

所以仔细检查这些事情:

  1. grant_type应该是吗authorization_code
  2. 您确定@authorization_code设置为一个值(而不是 nil)并且该值有效吗?
  3. 同样的问题@client_id
  4. 同样的问题@secret
  5. 你错过了一个redirect_uri价值吗?
于 2017-04-06T19:43:55.950 回答