问题
I am building a Rails API and am currently using doorkeeper and devise to authenticate users with the ResourceOwnerFromCredentials flow. All works fine however, I cannot get the authentication to work in Rspec.
Here is how am integrating the app in rspec:
let(:app_country) { FactoryGirl.create(:app_country)}
let(:valid_attributes) { FactoryGirl.attributes_for(:app_city, {:app_country_id => app_country.id}) }
let(:valid_session) { {:format => :json} }
let(:application) { Doorkeeper::Application.create!(:name => "App HQ dashboard", :redirect_uri => "https://localhost:3000/callback") }
let(:hq_user) { app_country.hq_users.create!(FactoryGirl.attributes_for :hq_user) }
let(:token) { Doorkeeper::AccessToken.create! :application_id => application.id, :resource_owner_id => hq_user.id }
But each time I try to test a protected action, the tests fail and I get the following output from the console:
Filter chain halted as :doorkeeper_authorize! rendered or redirected
Completed 403 Forbidden in 5ms (ActiveRecord: 1.2ms)
This was working fine with the previous version of doorkeeper. The tests broke when I upgraded the doorkeeper gem. What am I doing wrong? Or is there a new way of testing doorkeeper protected controllers?
UPDATE
Below is an actual test sample
describe "POST create" do
describe "with valid params" do
it "creates a new AppCity" do
expect {
post :create, {:app_city => valid_attributes, :v => "HEAD", :payload_type => "NODE", :access_token => token.token}, valid_session
}.to change(AppCity, :count).by(1)
end
it "persists the AppCity" do
post :create, {:app_city => valid_attributes, :v => "HEAD", :access_token => token.token}, valid_session
response_body = JSON.parse(response.body, symbolize_names: true)
expect(response_body[:id]).to be_present
end
it "returns a 201 status" do
post :create, {:app_city => valid_attributes, :v => "HEAD", :access_token => token.token}, valid_session
response.status.should eq(201)
end
end
describe "with invalid params" do
it "returns validation error message" do
post :create, {:app_city => { "name" => "" }, :v => "HEAD", :access_token => token.token}, valid_session
response_body = JSON.parse(response.body, symbolize_names: true)
expect(response_body[:name]).to include "can't be blank"
end
it "returns a 422 status" do
post :create, {:app_city => { "name" => "" }, :v => "HEAD", :access_token => token.token}, valid_session
response.status.should eq(422)
end
end
end
回答1:
I finally found the problem. I was getting a 403 Forbidden
because my I was sending a request with insufficient scope. I had defined the following scopes in doorkeeper.rb
# Define access token scopes for your provider
# For more information go to https://github.com/applicake/doorkeeper/wiki/Using-Scopes
default_scopes :public
optional_scopes :write, :update
For my specs to pass again I had to specify which actions required a specific access token scope e.g:
class Api::V1::ProductsController < Api::V1::ApiController
before_action -> { doorkeeper_authorize! :public }, only: :index
before_action only: [:create, :update, :destroy] do
doorkeeper_authorize! :admin, :write
end
end
I initially only had before_action :doorkeeper_authorize!, except: [:index, :show]
. What I needed to do was define the :write
and :update
scopes on the :create
, :update
and :destroy
actions. Or alternatively do away with the scopes completely.
I am also using CanCanCan so I guess the scopes should be redundant in my case.
Further reading here
来源:https://stackoverflow.com/questions/31787412/filter-chain-halted-as-doorkeeper-authorize-rendered-or-redirected