2013-01-03 1 views
0
나는 Farm 모델에 대한 사용자 인증을 테스트하기 위해 노력하고

다른 응답을 반환 사용자 일명 익명도 있음).캉캉 accessibly_by는 게스트로 (<strong>은 로그인 한되는 모든 농장</strong> 읽기 액세스 권한이있는 <code>:user</code> 역할이 경우, 스펙 및 컨트롤러

# /models/ability.rb 
class Ability 
    include CanCan::Ability 

    def initialize(user) 
    # Create guest user aka. anonymous (not logged in) when user is nil. 
    user ||= User.new 

    if user.has_role? :admin 
     can :manage, :all 
    else # guest user aka. anonymous 
     can :read, :all 
     # logged in user 
     if user.has_role? :user 
     can :create, Farm 
     can :manage, Farm, :user_id => user.id 
     end 
    end 

    end 
end 

...

# /controllers/api/v1/farms_controller.rb 
class Api::V1::FarmsController < ActionController::Base 

    load_and_authorize_resource 
    rescue_from CanCan::AccessDenied do |exception| 
     redirect_to farms_path, alert: exception.message 
    end 
    respond_to :json 

    def index 
     # Next line might be redundant refering to the CanCan wiki. See below.. 
     @farms = Farm.accessible_by(current_ability, :read) 
     respond_with(@farms) 
    end 
end 

...

# /spec/api/v1/farm_spec.rb 
require "spec_helper" 

describe "/api/v1/farms" do 
    let(:user) { create(:user) } # lets call this user1 in the discussion 
    let(:token) { user.authentication_token } 

    before do 
     user.add_role :user 
     create(:farm, user: user, name: "Testfarm") 
     create(:farm, name: "Access denied") 
     @ability = Ability.new(user) 
    end 

    context "farms viewable by this logged-in user" do 
     let(:url) { "/api/v1/farms" } 
     it "json" do 
      get "#{url}.json" 

      farms_json = Farm.accessible_by(@ability, :read).to_json 

      assert last_response.ok? 
      last_response.body.should eql(farms_json) 
      last_response.status.should eql(200) 

      farms = JSON.parse(last_response.body) 

      farms.any? do |farm| 
       farm["name"] == "Testfarm" 
      end.should be_true 

      farms.any? do |farm| 
       farm["name"] == "Access denied" 
      end.should be_true 

     end 
    end 
end 

문제

내가 farms_json을 검사

가 나는 Testfarm이 포함되어 볼 수 있습니다. 내가 last_response을 검사 할 때, 그것이 Testfarm Access denied을 포함하고있는 것을 볼 수있다. 동일한 accessible_by 메서드를 사용하여 동작과 index 동작을 모두 사용하기 때문에 이상합니다. 내가 사용하는 설정은 Fetching Records이라는 CanCan 보석의 위키에 설명되어 있습니다.

무용 한 해결 방법

내가 같은 농장 Access denied에 사용자 user에게 추가

...

create(:farm, user: user, name: "Access denied") 

... 다음 테스트가 성공합니다.

질문은 IT가 (게스트 사용자를 포함하여) 모든 사용자가 읽을 수 있지만하지 반환 농장 "액세스가 거부되었습니다"왜

?
  • get "#{url}.json"은 실제로 사용자의 상태를 고려합니까? 이 모든 작업이 의 load_and_authorize_resource으로 완료 되었습니까?
  • wiki mentions@farms = Farm.accessible_by(current_ability, :read)은 "이것은 색인 작업을 위해 load_resource에 의해 자동으로 수행됩니다"때문에 생략 할 수 있습니다. 이것은 내 상황에 적용 되는가?
  • 실험

    나는 다른 사용자 "사용자 2"다른 농장 "내 작은 농장"을 만들었습니다. 나는 그들을 서로 연결했다.

    • 농장 "Testfarm"사용자 2에 관련된 사용자
    • 농장 "내 작은 농장"에 관련된 "액세스가 거부되었습니다"
    • 농장의 user1에 관련된 :이 방법은 예제의 데이터베이스는 alltogether 세 개의 농장이 포함되어 있습니다.

    Farm.accessible_by(Ability.new(user1), :read)을 실행해도 "Testfarm"만 나타납니다.

    답변

    0

    내 질문에 대한 답은 여러 부분으로 구성됩니다. 비슷한 구성을 다루는 다른 모든 사람들에게 설정을 명확히하기를 바랍니다.모든

    1. 능력의 우선 순위

    첫 번째는 order of ability rules does matter as described in Ability Precedence 그 마음하시기 바랍니다. 이 사실을 깨닫고 나는 능력 규칙의 업데이트 된 세트를 생각해 냈습니다.

    # /models/ability.rb 
    class Ability 
        include CanCan::Ability 
    
        def initialize(user) 
        # Create guest user aka. anonymous (not logged-in) when user is nil. 
        user ||= User.new 
    
        if user.has_role? :admin 
         can :manage, :all 
        else 
         # logged in user 
         if user.has_role? :user 
         can :manage, Farm, :user_id => user.id 
         can :create, Farm 
         end 
         # guest user aka. anonymous 
         can :read, :all 
        end 
        end 
    end 
    

    2. FarmsContoller는

    인덱스 작업에 간단하십시오. load_and_authorize_resource은 당신의 친구입니다. 당신이 농장 컨트롤러에서 데이터를 요청할 때

    토큰 인증을

    # /controllers/api/v1/farms_controller.rb 
    class Api::V1::FarmsController < ActionController::Base 
    
        load_and_authorize_resource 
        rescue_from CanCan::AccessDenied do |exception| 
         redirect_to farms_path, alert: exception.message 
        end 
        respond_to :json 
    
        def index 
         respond_with(@farms) 
        end 
    end 
    

    3. GET 요청은 토큰을 전달하는 것을 잊지 마십시오.

    # # /spec/api/v1/farm_spec.rb 
    get "#{url}.json", auth_token: :token 
    

    다음과 같이 사용자 모델에 토큰을 추가해야합니다.

    # app/models/user.rb 
    class User < ActiveRecord::Base 
        before_save :ensure_authentication_token 
    

    그리고 메서드의 이름은 Devise의 초기화 프로그램에서 구성 할 수 있습니다.

    # config/initializers/devise.rb 
    config.token_authentication_key = :auth_token