我的omniauth应用程序的行为很奇怪。基本上,我有一个管理面板,需要对其进行访问,才能使用yandex帐户进行身份验证。
问题:我按照多个指南中的要求做了所有事情,从昨天开始,我尝试使用yandex帐户进行身份验证,结果收到httpbadrequest错误。
注意:我的代码一点也没变。我的所有访问数据客户端的ID和密码也没有更改。
Gemfile:

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部分的注册应用。然后用新的客户机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\u description”:“代码已过期”,“error”:“无效的授予”}
更新4:
我再次检查了Yandex的所有凭据客户端ID和密码,它们100%有效。

最佳答案

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 site上有进一步的解释:
无法颁发访问令牌。临时授权码不是由yandex.money颁发的,或者已经过期,或者已经为此临时授权码颁发了访问令牌(使用相同临时授权码的访问令牌的重复请求)。
您正在向yandex提供无效凭据。暂时忘记您编写的代码,因为唯一失败的部分是当它将数据发送到yandex时。Yandex告诉你数据无效,你已经和邮递员确认过了。这意味着发送的数据无效:
@post_body = "grant_type=authorization_code&code=#{@authorization_code}&client_id=#{@client_id}&client_secret=#{@secret}"

所以仔细检查一下:
grant_type应该是authorization_code吗?
您确定@authorization_code设置为一个值(而不是零)并且该值有效吗?
对于@client_id
同样的问题?
是否缺少@secret值?

关于ruby-on-rails - 用于Oauth身份验证的HTTPBadRequest {“error_description”:“代码已过期”,“error”:“invalid_grant”},Ruby on Rails,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/43203055/

10-09 10:04