自定义Rails路由使CanCan权限无效

时间:2014-03-18 15:22:23

标签: ruby-on-rails ruby permissions routes cancan

我正在开发一个拥有多种用户的项目,每个用户都附加到一个机构,每个用户都拥有自己的一组权限。最近,我开始更改Rails路由,以便不是传递:id我在机构的URL参数中传递自定义:identifier。我让它正常工作,机构正在更新和正确加载等等。然而,当我运行我的规范测试时,我意识到权限不再有效。例如,最受限制的用户级别,Institutional_Users应该无法加载任何机构的显示页面,除了他们自己,现在他们可以看到任何人的。我对如何解决这个问题感到茫然。

以下是我的Institutions_Controller。第一个set_institution方法是我为处理新参数而编写的方法,第二个方法是原始方法。

class InstitutionsController < ApplicationController
  inherit_resources
  load_and_authorize_resource
  before_filter :authenticate_user!
  before_action :set_institution, only: [:show, :edit, :update, :destroy]
  #before_action :get_institution, only: [:show, :edit, :update, :destroy]

  include Blacklight::SolrHelper

  # DELETE /institutions/1
  # DELETE /institutions/1.json
  def destroy
    #@institution = set_institution
    name = @institution.name
    destroy!(notice: "#{name} was successfully destroyed.")
  end



  private
    def set_institution
      if params[:identifier].nil?
        @institution = current_user.institution
      elsif Institution.where(desc_metadata__identifier_tesim: params[:identifier]).empty?
        @institution = current_user.institution
        flash[:alert] = "That institution does not exist."
      else
        @institution = Institution.where(desc_metadata__identifier_tesim: params[:identifier]).first
      end
    end

    # If an id is passed through params, use it.  Otherwise default to show a current user's institution.
    #def set_institution
    #  @institution = params[:id].nil? ? current_user.institution : Institution.find(params[:id])
    #end

    # Never trust parameters from the scary internet, only allow the white list through.
    def build_resource_params
      params[:action] == 'new' ? [] : [params.require(:institution).permit(:name, :identifier)]
    end

end

我将此添加到我的Institution Model,以便正确参数化:

def to_param
  identifier
end

这是我的User Model,删除了一些非必要的方法(我不应该,我们正在为用户使用Devise

要求'bcrypt'

class User < ActiveRecord::Base
  # Connects this user object to Hydra behaviors. 
  include Hydra::User

  # Connects this user object to Blacklights Bookmarks. 
  include Blacklight::User
  include Aptrust::SolrHelper

  # Connects this user object to Role-management behaviors. 
  include Hydra::RoleManagement::UserRoles

  # Include default devise modules. Others available are:
  # :database_authenticatable,
  # :recoverable, :rememberable, :trackable, :validatable,
  # :token_authenticatable, :confirmable,
  # :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :recoverable, :rememberable, :trackable, :timeoutable

  validates :email, :phone_number, presence: true
  validates :email, uniqueness: true
  validates :institution_pid, presence: true
  validate :institution_pid_points_at_institution

  # Custom format validations.  See app/validators
  validates :name, person_name_format: true, if: ->{ name.present? }
  validates :email, email: true

  # Handle and normalize phone numbers
  phony_normalize :phone_number, :default_country_code => 'US'

  validates :phone_number, :phony_plausible => true

  # This method assigns permission groups
  def groups
    super + institution_groups
  end

  def institution_groups
    if institutional_admin?
      ["Admin_At_#{institution_group_suffix}"]
    elsif institutional_user?
      ["User_At_#{institution_group_suffix}"]
    else
      []
    end
  end

  def institution_identifier
    institution = Institution.find(self.institution_pid)
    institution.identifier
  end

  # Blacklight uses #to_s on youruser class to get a user-displayable 
  # login/identifier for the account. 
  #
  # Method modified from the Blacklight default.
  def to_s
    name || email
  end

  # Roles are managed through the hydra-role-management gem.
  def is?(role)
    self.roles.pluck(:name).include?(role.to_s)
  end

  def admin?
    is? 'admin'
  end

  def institutional_admin?
    is? 'institutional_admin'
  end

  def institutional_user?
    is? 'institutional_user'
  end


  # Since an Institution is an ActiveFedora Object, these two objects cannot be related as normal (i.e. belongs_to)
  # They will be connected through the User.institution_pid.
  def institution
    @institution ||= Institution.find(self.institution_pid)
  rescue ActiveFedora::ObjectNotFoundError => e
    logger.warn "#{self.institution_pid} is set as the institution for #{self}, but it doesn't exist"
    @institution = NilInstitution.new
  end

  def institution_group_suffix
    clean_for_solr(institution_pid)
  end

  class NilInstitution
    def name
      "Deleted Institution"
    end

    def to_param
      'deleted'
    end

    def brief_name
      "Deleted Institution"
    end

    def users
      []
    end

    def intellectual_objects
      []
    end

    def bytes_by_format
      {}
    end
  end

  private

  def institution_pid_points_at_institution
    errors.add(:institution_pid, "is not a valid institution") unless Institution.exists?(institution_pid)
  end

end

这是设置用户权限的Ability Model。您可以看到我尝试添加新行以处理标识符参数的位置而没有任何运气。

class Ability
  include Hydra::Ability

  # customizing permissions as directed:
  # https://github.com/projecthydra/hydra-head/blob/master/hydra-access-controls/lib/hydra/ability.rb
  self.ability_logic +=[:admin_permissions, :institutional_admin_permissions, :institutional_user_permissions]


  def create_permissions
    # nop - override default behavior which allows any registered user to create
  end

  def admin_permissions
    if current_user.is? :admin
      can :manage, :all 
    end
  end

  def institutional_admin_permissions
    if current_user.is? :institutional_admin
      can :add_user, Institution, id: current_user.institution_pid
      can :add_user, Role, name: 'institutional_user'
      can :add_user, Role, name: 'institutional_admin'
      can [:read, :update, :destroy], User, institution_pid: current_user.institution_pid
      can [:create], User
      can :generate_api_key, User, id: current_user.id
      can [:read, :update], Institution, pid: current_user.institution_pid
      can :create, GenericFile, :intellectual_object => { :institution_id => current_user.institution_pid }
      can :create, IntellectualObject, institution_id: current_user.institution_pid
    end
  end

  def institutional_user_permissions
    if current_user.is? :institutional_user
      can :manage, User, id: current_user.id
      can :read, Institution, pid: current_user.institution_pid
      #can :read, Institution, identifier: current_user.institution_identifier
    end
  end

end

如果我遗漏了某些内容,或者我需要添加其他任何代码,请告知我们。谢谢!

编辑:

我在Institution Controller set_institution方法中添加了这一行:

authorize! [:show, :edit, :update, :destroy], @institution

新方法如下所示:

def set_institution
  if params[:institution_identifier].nil?
    @institution = current_user.institution
  elsif Institution.where(desc_metadata__institution_identifier_tesim: params[:institution_identifier]).empty?
    @institution = current_user.institution
    flash[:alert] = "That institution does not exist."
  else
    @institution = Institution.where(desc_metadata__institution_identifier_tesim: params[:institution_identifier]).first
    authorize! [:show, :edit, :update, :destroy], @institution
  end
end

现在,机构用户无法查看所有机构,如果他们访问网址,则无法看到任何机构,例如localhost:3000/institutions/columbia。有趣的是,当发生这种情况时,页面会重定向到根,这恰好是机构显示页面。因此,用户仍然可以访问他们自己的机构,但仅限于授权声明的位置。似乎添加授权行使得机构用户无法做任何事情而拿走它允许他们做任何事情。

1 个答案:

答案 0 :(得分:0)

在类似的情况下,我用以下方法解决了这个问题:

load_and_authorize_resource :find_by => :identifier

在控制器中。

请参阅:https://github.com/CanCanCommunity/cancancan/wiki/Authorizing-controller-actions#custom-find