簡體   English   中英

HTTPBadRequest {“error_description”:“代碼已過期”,“錯誤”:“invalid_grant”}用於Oauth身份驗證,Ruby on Rails

[英]HTTPBadRequest {“error_description”: “Code has expired”, “error”: “invalid_grant”} for Oauth authentification, Ruby on Rails

我的omniauth應用程序有奇怪的行為。 基本上,我有管理員面板,需要訪問它才能使用Yandex帳戶進行身份驗證。

問題 :我在多個指南中按要求完成了所有操作,一切正常,因為昨天我嘗試使用Yandex帳戶進行身份驗證,並收到了HTTPBadRequest錯誤。

注意 :我的代碼中沒有改變。 我的所有訪問數據client_Id和密碼都沒有改變。

的Gemfile:

gem "omniauth-yandex"

路線:

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

CallbacksController:

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”:“代碼已過期”,“錯誤”:“invalid_grant”}

更新4:

我再次檢查了Yandex的所有憑據client_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網站上進一步解釋:

無法發出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值嗎?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM