【问题标题】:Issue with JSON request - rails/faradayJSON 请求的问题 - rails/faraday
【发布时间】:2017-03-31 15:34:09
【问题描述】:

当我尝试接收应该包含在来自外部 Api 的 JSON 响应中的访问令牌时,我遇到了 rails 和 faraday 问题。

我想做的是基于外部 API 的用户身份验证。 我假设用户已经拥有有效的凭据(在这种情况下,电子邮件作为用户名和密码)。

现在当他连接到我的 Api 时,我向外部 Api 发送 JSON 请求以验证此用户是否有效并等待访问令牌。

在响应中发送访问令牌后,用户身份验证成功并且我可以访问其他端点

这是我的控制器

module Api
  class AuthenticationController < ApplicationController
    def create 
      client = XXX::AuthClient.new

      response = client.authenticate(
        email: params[:email],
        password: params[:password]
      )

      api_client = XXX::Client.new(response[:access_token])

      if response[:access_token]
        api_user = api_client.get_user()

        if api_user["id"]
          db_user = User.create(xxx_id: api_user["id"], xxx_access_token: response[:access_token])
        end
      end

      render json: { access_token: db_user.access_token }
    end
  end
end

这是我的 AuthClient 服务

class AuthClient
    def initialize
      @http_client = Faraday.new('https://auth.xxx.com/')
    end

    def authenticate(email:, password:)
      headers = {
        'Content-Type': 'application/json'
      }.to_json

      body = {
        grant_type: "password",
        username: email,
        password: password,
        client_id: "particularclientid",
        client_secret: "particularclientsecret"
      }.to_json

      api_response = http_client.post("/oauth2/token", body)
      response = JSON.parse(api_response.body)

      if response["access_token"]
        { access_token: access_token }
      else
        { error: "autentication error" }
      end

    end

    private

    attr_reader :http_client
  end
end

我知道以下格式的 curl 是正确的,我可以看到用户的访问令牌、刷新令牌等。

curl -X POST -H "Content-Type: application/json" -d '{
"grant_type": "password",
"username": "test+user@example.com",
"password": "examplepassword",
"client_id": "particularclientid",
"client_secret": "particularclientsecret"
}' "https://auth.xxx.com/oauth2/token"

但是当我运行 curl 时

curl -X POST -d 'email=test+user@example.com&password=examplepassword' "http://localhost:3000/api/auth"

我发现我的请求不正确。但我不知道问题出在哪里,因为标题和正文已格式化为 JSON(我已输入 puts headersputs bodyputs response 来验证这一点)。

Started POST "/api/auth" for 127.0.0.1 at 2017-03-31 16:42:26 +0200
Processing by Api::AuthenticationController#create as */*
  Parameters: {"email"=>"test user@example.com", "password"=>"[FILTERED]"}
{"Content-Type":"application/json"}
{"grant_type":"password","username":"test user@example.com","password":"examplepassword","client_id":"particularclientid","client_secret":"particularclientsecret"}
{"error"=>"invalid_request", "error_description"=>"The request is missing a required parameter, includes an unsupported parameter value, or is otherwise malformed."}
Completed 500 Internal Server Error in 610ms (ActiveRecord: 0.0ms)


NoMethodError (undefined method `access_token' for nil:NilClass):

app/controllers/api/authentication_controller.rb:21:in `create'

是我的请求不正确还是问题存在于其他地方? 我不是经验丰富的开发人员。只是想学习足够的知识以作为初级 RoR 开始。我试图在堆栈和不同站点上找到解决方案,但我被困住了。即使是法拉第文档也对我没有多大帮助

【问题讨论】:

  • 在代码块“AuthClient 服务”中,您设置了 headers 变量,但没有在请求中使用它。对吗?

标签: ruby-on-rails json curl faraday


【解决方案1】:

好的。 当我再次开始阅读我的帖子时,我又发现了一个问题。

我的控制器无法识别用户名字段中的加号,它被空格替换。 在我的卷曲中,我发送curl -X POST -d 'email=test+user@example.com&amp;... 在控制器中我看到"username":"test user@example.com"

但这并不能解决我的问题。

【讨论】:

    【解决方案2】:

    当 URI 被转义时,+ 被用作空格的替代品。因此,当您的控制器取消转义 URI 时,+ 会变回空格。如果要发送空间,请改用%2B

    对于您的第一个问题,当您尝试执行db_user.access_token 时,错误消息表明db_user 为nil。所以,要么response[:access_token] 为nil,api_user["id"] 为nil,要么User.create 失败。

    您需要进行一些调试以找出问题所在。

    【讨论】:

    • I, [2017-04-01T00:50:34.680829 #23770] INFO -- : post https://auth.xxx.com/oauth2/token D, [2017-04-01T00:50:34.681004 #23770] DEBUG -- request: User-Agent: "Faraday v0.11.0" D, [2017-04-01T00:50:34.681299 #23770] DEBUG -- request: {"grant_type":"password","username":"test user@example.com","password":"examplepassword","client_id":"particularclientid","client_secret":"particularclientsecret"}
    • 嗯,看起来我的标头甚至没有发送给客户端。
    【解决方案3】:

    我已经调试了我的控制器,当我在控制台中打印响应时看到了这一点

    response = client.authenticate(
      email: params[:email],
      password: params[:password]
    )
    
    puts response
    

    我收到{:error=&gt;"autentication error"}。 那么这意味着当我将请求发送到客户端的 Api 时,我收到一个错误而不是访问令牌

    if response["access_token"]
      { access_token: access_token }
    else
      { error: "autentication error" }
    end
    

    所以在这种情况下唯一可能出错的是我的请求格式不正确(应该是 JSON),或者在标题或正文中缺少某些内容。

    def authenticate(email:, password:)
      headers = {
        'Content-Type': 'application/json'
      }.to_json
    
      body = {
        grant_type: GRANT_TYPE,
        username: email,
        password: password,
        client_id: CLIENT_ID,
        client_secret: CLIENT_SECRET
      }.to_json
    
      api_response = http_client.post("/oauth2/token", body)
      response = JSON.parse(api_response.body)
    

    是否有可能验证这里发送的内容? api_response = http_client.post("/oauth2/token", body) 我已经尝试在此代码下方插入 puts,但在控制台中什么也看不到。

    【讨论】:

    • 请注意,所有正文值都是正确的,因此授权类型、用户名、密码、客户端 ID 和客户端密码都可以。我的标头或正文是否有可能不是以 JSON 格式发送的?或者,我的标头没有被发送,所以我的请求每次都会失败。
    猜你喜欢
    • 2015-04-17
    • 1970-01-01
    • 1970-01-01
    • 2014-01-13
    • 1970-01-01
    • 1970-01-01
    • 2020-07-18
    • 1970-01-01
    • 2016-06-10
    相关资源
    最近更新 更多