【问题标题】:Doorkeeper /oauth/token - blank responseDoorkeeper /oauth/token - 空白响应
【发布时间】:2013-11-22 11:48:18
【问题描述】:

我在 AngularJS 中有一个前端,在 RoR 中有一个带有 Devise + Doorkeeper + RocketPants 的后端。 现在我有正常工作的 CORS,我可以成功地从我的 API 获得 json 响应(如果我关闭门卫保护)。但现在我正在尝试实现用户密码凭证流程:

在门卫上:

  resource_owner_from_credentials do |routes|
    request.params[:user] = {:email => request.params[:username], :password => request.params[:password]}
    request.env["devise.allow_params_authentication"] = true
    request.env["warden"].authenticate!(:scope => :user)
  end

关于 angularjs (src: nils-blum):

var payload = "username="+username+"&password="+password+"&" +
        "client_id="+client_id+"&client_secret="+client_secret+
        "&grant_type=password"

$http({method: 'POST',
    url: scope.booksh_server + '/oauth/token',
    data:   payload,
    headers: {'Content-Type':'application/x-www-form-urlencoded'}
    }
).success(function (data) {
            tokenHandler.set(data.access_token);
            scope.$broadcast('event:authenticated');
});

注意:Nils 的方法使用有效负载作为带有参数的对象,而不是字符串。就我而言,它给了我带有有效负载的 POST,而不是带有 FORM 参数,因此无法正常工作。

当我输入错误的用户/密码时,rails 日志显示:

    Started POST "/oauth/token" for 127.0.0.1 at 2013-11-22 15:21:08 +0400
  Doorkeeper::Application Load (0.5ms)  SELECT "oauth_applications".* FROM "oauth_applications" WHERE "oauth_applications"."uid" = '981d6d654f5e709b2ca3437401c993a6d09cc91cc3fb16b8e2b3191e6421029c' AND "oauth_applications"."secret" = 'f92c4ec969525352bd03ec1eb810a9952cd0814d37ce5b2b02e8a928b2561e10' ORDER BY "oauth_applications"."id" ASC LIMIT 1
  User Load (0.9ms)  SELECT "users".* FROM "users" WHERE "users"."email" = 'undefined' ORDER BY "users"."id" ASC LIMIT 1

Chrome 开发工具将此请求显示为已取消。 Firebug 显示 302 Found 状态的空响应。当我从 chrome REST App 执行相同的 POST 时,UPD: server 也会这样做,我得到 302 Found,然后它被重定向到设计的登录页面。

此外,如果我输入正确的用户名/密码,firefox 会显示 200 OK 的空响应,REST 会收到带有访问令牌的正确 json,chrome 会显示取消响应并抛出 CORS 错误:

XMLHttpRequest cannot load http://0.0.0.0:3000/oauth/token. Origin http://0.0.0.0:9000 is not allowed by Access-Control-Allow-Origin. 

服务器日志:

Started POST "/oauth/token" for 127.0.0.1 at 2013-11-22 15:33:22 +0400
  Doorkeeper::Application Load (0.5ms)  SELECT "oauth_applications".* FROM "oauth_applications" WHERE "oauth_applications"."uid" = '981d6d654f5e709b2ca3437401c993a6d09cc91cc3fb16b8e2b3191e6421029c' AND "oauth_applications"."secret" = 'f92c4ec969525352bd03ec1eb810a9952cd0814d37ce5b2b02e8a928b2561e10' ORDER BY "oauth_applications"."id" ASC LIMIT 1
  User Load (0.5ms)  SELECT "users".* FROM "users" WHERE "users"."email" = '123@gmail.com' ORDER BY "users"."id" ASC LIMIT 1
   (0.2ms)  BEGIN
  SQL (0.4ms)  UPDATE "users" SET "last_sign_in_at" = $1, "current_sign_in_at" = $2, "sign_in_count" = $3, "remember_token" = $4, "updated_at" = $5 WHERE "users"."id" = 1  [["last_sign_in_at", Fri, 22 Nov 2013 11:32:49 UTC +00:00], ["current_sign_in_at", Fri, 22 Nov 2013 11:33:23 UTC +00:00], ["sign_in_count", 24], ["remember_token", "N5sRI6vE7B6vRNUlih3G2Q"], ["updated_at", Fri, 22 Nov 2013 11:33:23 UTC +00:00]]
   (17.5ms)  COMMIT
   (1.6ms)  BEGIN
  Doorkeeper::AccessToken Exists (0.3ms)  SELECT 1 AS one FROM "oauth_access_tokens" WHERE "oauth_access_tokens"."token" = '72dd81fd85b638fb14f9d081193b1eda0e58f85d6820718ab635fe195c36a689' LIMIT 1
  SQL (0.3ms)  INSERT INTO "oauth_access_tokens" ("application_id", "created_at", "expires_in", "resource_owner_id", "scopes", "token") VALUES ($1, $2, $3, $4, $5, $6) RETURNING "id"  [["application_id", 1], ["created_at", Fri, 22 Nov 2013 11:33:23 UTC +00:00], ["expires_in", 7200], ["resource_owner_id", 1], ["scopes", ""], ["token", "72dd81fd85b638fb14f9d081193b1eda0e58f85d6820718ab635fe195c36a689"]]
   (28.1ms)  COMMIT

我怎样才能做到这一点?如果电子邮件/密码正确,我需要 POST /oauth/token 来处理身份验证并使用 access_token 进行响应。 感谢任何帮助,我已经厌倦了被困在这个问题上)

【问题讨论】:

  • 好问题!不幸的是,其中涉及的宝石太多,要找到答案需要投入大量时间。
  • Nils 的方法使用有效负载作为带有参数的对象,而不是字符串。就我而言,它给了我带有有效负载的 POST,而不是带有 FORM 参数,因此不起作用。 - 我不明白这一点。用户名和密码存在于 POST 请求的有效负载数据中,这意味着您可以在服务器上提取它们。为什么说你的情况不一样?
  • 它会返回带有 access_token 的正确 json 对象。据我所知,这是因为请求提供了 cookie '_doorkeeper-provider_session',但我找不到在哪里销毁它。 - 对于单个测试,您可以简单地在浏览器的 cookie 中销毁它经理,看看它是否仍然有效。
  • @Chandranshu 我不知道为什么,但是如果我用字符串编码的参数发布,门卫会处理它,如果我使用对象 - 不(对象作为 json 发送,也许这就是问题所在。但我不明白,为什么 Nils 的文章使用这种方法)好​​吧,我找到了如何销毁 cookie - 它应该不是在休息客户端的页面上,而是在我的 api 页面上。销毁它,现在 REST 客户端请求被处理为来自 chrome 或 firefox 的正确请求,它再次返回正确的 json。似乎服务器在所有情况下都以相同的方式响应。我将使用不带 cookie 的案例更新帖子。
  • 听到服务器在两种情况下都以相同的方式响应,这让我们松了一口气,否则我们会拉扯耳朵和头发以使其保持一致。我仍然怀疑从浏览器发送到您的应用程序的内容是什么。有什么方法可以访问您的 API/站点?我需要从她的办公室接我的妻子回家。让我知道在 cmets 中是否可行,我们可以在聊天室中继续讨论。

标签: ruby-on-rails angularjs devise doorkeeper


【解决方案1】:

耶!最后我让它工作了。仍然不知道为什么在整个网络上的教程中它更容易。

所以,问题出在哪里:在我的 ApplicationController(根目录,而不是处理 API 的那个)中,我对 CORS 进行了以下操作:

  before_filter :set_headers

  def set_headers
    headers['Access-Control-Allow-Origin'] = 'http://0.0.0.0:9000'
    headers['Access-Control-Allow-Methods'] = 'GET, POST, PATCH, PUT, DELETE, OPTIONS, HEAD'
    headers['Access-Control-Allow-Headers'] = '*,X-Requested-With,Content-Type,If-Modified-Since,If-None-Match'
    headers['Access-Control-Max-Age'] = '86400'
  end

深入研究问题,我发现当我调用 /oauth/token 时不会调用此函数,但当我转到使用 ApplicationController 处理的 API 之外的任何其他路由时会调用此函数

Doorkeeper 有自己的控制器,独立于您的应用控制器。文档很好地描述了他们的行为变化 (link),所以这对我有帮助:

routes.rb:

use_doorkeeper do
    controllers tokens: 'custom_tokens'
end

custom_tokens_controller.rb:

class CustomTokensController < Doorkeeper::TokensController

  include AbstractController::Callbacks
  before_filter :set_headers

  def set_headers
    puts 'headers set'
    headers['Access-Control-Allow-Origin'] = 'http://0.0.0.0:9000'
    headers['Access-Control-Allow-Methods'] = 'GET, POST, PATCH, PUT, DELETE, OPTIONS, HEAD'
    headers['Access-Control-Allow-Headers'] = '*,X-Requested-With,Content-Type,If-Modified-Since,If-None-Match'
    headers['Access-Control-Max-Age'] = '86400'
  end
end

重要的是将Callbacks 包含到控制器中,因为Doorkeeper 控制器是从Metal 继承的,所以没有包含rails 就无法找到before_filter

现在看起来不错:它验证了我的用户/密码对,并返回 access_token(我希望它可以工作:D)。如果出现问题,现在应该重定向。这是我知道解决方案(自定义看守失败)的问题,所以现在一切正常。哼!很长...如果有人知道为什么基于互联网的食谱没有帮助,请发表您的想法=)

【讨论】:

  • 在客户端存储client_idclient_secret 似乎很不安全——你在生产中使用这种方法吗?我面临同样的情况:-/
  • 你好,克里斯。不幸的是,我在那个项目和 Rails 上都没有进一步发展,所以不,我没有这个在生产中。
猜你喜欢
  • 2018-05-04
  • 2014-08-30
  • 2014-09-29
  • 2012-11-04
  • 2020-07-21
  • 2014-10-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多