module AccessControl Options = {:class => :User, :roles => :role, :map => :name, :user => :user}; def self.included(klass) klass.class_eval do extend AccessControl::ClassMethods; end end def self.guest # Simple mock object Struct.new(Options[:roles]).new(Struct.new(Options[:map]).new(:guest)); end module ClassMethods def restrictions; @restrictions; end def check_user_by(param) lambda{current_user.id == params[param.to_sym].to_i;}; end def check_user; check_user_by(:id); end def access_control_setup(opts) opts[:class] = opts[:a] || opts[:an] || opts[:class]; opts[:roles] = opts[:has_one] || opts[:has_many] || opts[:role] || opts[:roles]; opts[:map] = opts[:map_its] || opts[:map]; opts[:user] = opts[:class].to_s.downcase.to_sym; AccessControl::Options.merge!(opts); end def restrict_access(opts={}, &check) opts = {:of => :all}.merge(opts); check ||= opts.delete(:check); (@restrictions ||= []) << AccessControl::Restriction.new(opts.delete(:of), opts.delete(:to), opts.delete(:from), check, opts); before_filter(:check_authorization) unless before_filters.include?(:check_authorization); end end class Restriction attr_reader :actions, :options; CheckDefault = lambda{true;}; @@options = AccessControl::Options; def initialize(actions, included_roles, excluded_roles, check=nil, opts={}) @actions = (actions == :all) ? actions : [actions].flatten.map(&:to_sym); @roles = [(included_roles || excluded_roles)].flatten.map(&:to_sym); @mode = ActiveSupport::StringInquirer.new((included_roles) ? "inclusive" : "exclusive"); @check = check || CheckDefault; @options = opts; end def ok?(user, action, controller) # Could be in one line, but it'd be a mess if @actions == :all or @actions.include?(action) set_check_for(user) if @check.kind_of?(Hash); ((@mode.inclusive? and (roles_of(user) & @roles).size > 0) or (@mode.exclusive? and (roles_of(user) & @roles).empty?)) and @check.bind(controller).call; else true; end end private def roles_of(user) [user.send(@@options[:roles])].flatten.map(&@@options[:map].to_sym).map(&:to_sym); end def set_check_for(user) #@check.flatten_keys!; @check = @check[(@check.keys & roles_of(user)).first] || CheckDefault; end end def check_authorization action = request.path_parameters[:action].to_sym; restriction = self.class.restrictions.detect do |restriction| !restriction.ok?(current_user || AccessControl.guest, action, self); end access_denied(restriction.options) if restriction; return !restriction; end def access_denied(opts) flash[:warning] = opts[:message] || "Você não tem permissão para acessar este recurso."; session[:redirect_to] = request.path; redirect_to(opts[:redirect_url] || login_path); end end