JSON请求问题 - rails / faraday

时间:2017-03-31 15:34:10

标签: ruby-on-rails json curl faraday

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

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

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

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

这是我的控制器

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 -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 -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。我试图在堆栈和不同的网站上找到解决方案,但我被困了。即使是法拉第文档对我也没有多大帮助

3 个答案:

答案 0 :(得分:0)

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

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

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

答案 1 :(得分:0)

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

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

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

答案 2 :(得分:0)

我调试了控制器,当我在控制台中打印响应时,我看到了

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

puts response

我收到了{:error=>"autentication error"}。 然后,这意味着当我向Client的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,我在控制台中看不到任何内容。