Frage

Ich bin auf der Suche nach dem besten Weg saubere Art und Weise zu bauen Rolle / authorisaton-basierten Findern zu bauen?

In meinem Modellschema, ein user einen von mehreren haben kann (Admin-definiert) Rollen wie Administrator, Regional Manager, Sales Assistant:

Beispiel: ein Benutzer mit einem Regional Manager Rolle gegeben und schloss sich zu einer Region A, würde Ich mag Lage sein, zu fragen, was andere Benutzer sie sehen konnte, z:

regional_manager_for_region_a.users 
  => [...] # Array of users joined to region a

regional_manager_for_region_b.users(:all, conditions => { :active => true })
  => [...] # Array of active users joined to region b

administrator.users
  => [...] # Array of all users in system

Danke, sehr zu schätzen jede Hilfe!

War es hilfreich?

Lösung

Ich glaube, Sie müssen an Ort und Stelle eine Autorisierungsmechanismus setzen.

Die beste gem ich für diese wissen, ist declarative_authorization . Ich habe persönlich es in einer Produktionsumgebung verwendet wird, und ich bin damit zufrieden. Es gibt einen Railscast über es auch.

Die Idee ist, dass Sie in einer bestimmten Datei (config/authorization_rules.rb) die „Rollen und Berechtigungen“ deklarieren. Sie sagen Dinge wie „ein Manager nur die damit verbundenen Clients mit ihm lesen kann“ oder „kann ein Administrator alle Benutzer lesen und schreiben“. In Ihrem Fall würde es so aussehen:

authorization do

  role :guest do
    # actions here can be done by everyone, even not logged in people
  end

  role :user do
    includes :guest
    # actions here can be done by logged people
  end

  role :manager do
    includes :user #managers do everything users do, plus:

    has_permission_on :sales_region, :to => :read do
      if_attribute :id => is_in {user.sales_region_ids}
    end

    has_permission_on :users, :to => [:update, :read] do
      if_attribute :id => is {user.user_ids_by_sales_region} #defined on the model
    end
  end

  role :admin do
    includes :user
    has_permission_on [:sales_regions, :users], :to :manage
  end

end

privileges do
  privilege :manage do
    includes :create, :read, :update, :delete
  end
end

Sobald dies festgelegt ist, müssen Sie Ihre Modelle modifizieren, so dass sie declarative_authorization verwenden. Außerdem wollen wir die user_ids_by_sales_region Methode definieren

class User < ActiveRecord::Base

  using_access_control # this enables DA

  def users_by_sales_region
    sales_regions.collect{ |sr| sr.users }.flatten.uniq
  end

  def user_ids_by_sales_region
    users_by_sales_region.collect{ |u| u.id }
  end
end

Sie müssen auch eine current_user Methode haben, und einen Weg des aktuellen Benutzers Rolle des Erhaltens (n). Siehe "Die Anforderungen des Plugin Providing" auf der readme .

Dann können Sie tun, was Sie mit with_permissions_to wollen:

manager = User.find(...)
manager.users.with_permissions_to(:read) # the users from his region
manager.users.with_permissions_to(:read).find(:all, conditions => { :active => true })
manager.users.with_permissions_to(:write) #returns no users, managers can't edit them

admin = User.find(...)
admin.users.with_permissions_to(:write) #will return all users

Das bedeutet, ein wenig Aufwand am Anfang, aber die Anwendung vereinfacht später stark. Außerdem haben Sie zusätzliche Funktionalitäten, wie versteckt / Teile von Ansichten, die auf den Berechtigungen Aktionen der aktuelle Benutzer hat, sowie das Verbot des Zugriffs auf bestimmte Controller abhängig.

Auch sollte es gut funktionieren mit Seitenzahlen, etc.

Es gibt ein andere deklarative Genehmigung gem genannt Cancan . Ich habe keine Erfahrung mit diesem, aber wenn es von Ryan Bates getan wird, muss es gut sein (er hat eine Railscast es auch). Aber ich glaube nicht, erlaubt es Modellerweiterungen, das ist, was Sie scheinen jetzt zu müssen.

Andere Tipps

Meine Antwort unten ist gut für einfache Sucher; ist es jedoch nicht sehr flexibel und ist nicht kompatibel mit dem will_paginate Plugin. Kennt jemand einen besseren Weg, um sauber Umfang die Benutzer @current_user ist in der Lage zu verwalten?

Danke


Nur meine eigene Frage beantwortet, indem die Standardzuordnung Erweiterung überschreiben, wie unten. Es wäre noch toll, wenn Kommentare oder Alternativen zu wissen!

class User < ActiveRecord::Base
  has_many :users do
    def find(*args)
      scope = args.first || :all
      options = args.extract_options!

      return User.find(args.first, options) if proxy_owner.admin?

      users = []
      proxy_owner.sales_regions.collect do |sales_region|
        users += sales_region.users
      end

      users.uniq
    end
  end
end

Nur meinen Kommentar auf egarcia Antwort folgen zu lassen, ich erklärt named_scopes auf den eingeschränkten Modellen schließlich nieder. Zum Beispiel:

# app/models/account.rb
class Account < ActiveRecord::Base
  named_scope :visible_to, lambda { |user| 
    return {} if user.can_see_all_accounts?
    { :conditions => ['sales_area_id IN (?)', user.sales_area_ids] } 
  }
end

# app/controllers/accounts_controller.rb
class AccountsController < ApplicationController
  def index
    @accounts = Account.visible_to(@current_user)
    ...
  end
end
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top