2013-11-22 25 views
5

我有一個AngularJS的前端和RoR的Devise + Doorkeeper + RocketPants的後端。 現在我已經正常工作CORS,我可以成功地從我的API中獲得json響應(如果我關閉門衛保護)。但現在我想實現用戶密碼憑證流:門衛/ oauth /令牌 - 空白回覆

在門衛:

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'); 
}); 

注:尼爾斯的方法是使用有效載荷爲對象與params,而不是一個字符串。在我的情況下,它給我帶有有效載荷的POST,而不是FORM PARAMS,因此無法工作。

當我輸入錯誤的用戶名/密碼,登錄導軌說:

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:服務器執行相同的操作,並且獲得302 Found,然後將其重定向到設備的sign_in頁面。

而且,如果我輸入正確的用戶名/密碼,火狐顯示了200 OK空響應,REST接收與訪問令牌正確的JSON和鉻顯示取消響應,並拋出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" = '[email protected]' 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進行響應。 任何幫助表示讚賞,我厭倦了卡住在此)

+0

偉大的問題!不幸的是,有這麼多的寶石,找到答案將需要巨大的時間投入。 – Chandranshu

+0

* Nils的方法使用有效載荷作爲帶參數的對象,而不是字符串。在我的情況下,它給我帶有有效負載的POST,而不是FORM PARAMS,因此無法工作。* - 我不明白這一點。用戶名和密碼出現在POST請求的有效負載數據中,這意味着您可以在服務器上提取它們。你爲什麼說你的情況不同? – Chandranshu

+0

*然後它返回適當的json對象與access_token。據我所知,這是因爲Cookie提供了'_doorkeeper-provider_session',隨請求一起提供,但我找不到,在哪裏銷燬它。* - 對於單個測試,您可以簡單地在瀏覽器的Cookie管理器中銷燬它並查看如果它仍然有效。 – Chandranshu

回答

8

Yay!最後我做了它的工作。仍然不知道爲什麼在網絡上的教程,它更容易。

所以,那裏的問題來自於:在我爲CORS下面我ApplicationController(根一個,而不是處理API的一個):

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 /令牌時沒有被呼叫,但當我去到API之外的任何其他路由時被呼叫,ApplicationController

門衛有它自己的控制器獨立於你的應用控制器。文檔描述了他們的行爲改變以及(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進入控制器,因爲門衛控制器是從Metal繼承的,所以沒有包含導軌找不到before_filter

它現在看起來不錯:它認證我的用戶/密碼對,並返回access_token(我希望,它的工作原理:D)。如果出現問題,現在應該重定向。這是我知道的解決方案(定製監獄失敗)的問題,所以現在一切正常。咦!這是很長的...如果有人知道爲什麼基於互聯網的食譜沒有幫助,請張貼您的想法=)

+0

存儲'client_id'和'client_secret'客戶端似乎很不安全 - 你在生產中使用這種方法嗎?我面臨同樣的情況: -/ –

+0

你好,克里斯。不幸的是,我沒有對這個項目和Rails做任何進一步的調整,所以不,我沒有這個產品。 – ProdoElmit