Yet another role-based authorization system for Rails
Acl9 is a role-based authorization system that provides a concise DSL for securing your Rails application.
Access control is pointless if you're not sure you've done it right. The fundamental goal of acl9 is to ensure that your rules are easy to understand and easy to test - in other words acl9 makes it easy to ensure you've got your permissions correct.
Acl9 is Semantically Versioned, so just add this to your
Gemfile (note that you need 3.2 for Rails 6+ support):
gem 'acl9', '~> 3.2'We're only testing with Ruby >= 3.1 so YMMV for less than that
gem 'acl9', '~> 2.0'
## Getting Started
The simplest way to demonstrate this is with some examples.
### Access Control
You declare the access control directly in your controller, so it's visible and
obvious for any developer looking at the controller:
```ruby
class Admin::SchoolsController School
allow :admins, :managers, :teachers, :of => :school
deny :teachers, :only => :destroy
action :index do
allow anonymous, logged_in
end
allow logged_in, :only => :show
deny :students
end
def index
# ...
end
# ...
endYou can see more about all this stuff in the wiki under Access Control Subsystem
The other side of acl9 is where you give and remove roles to and from a user. As you're looking through these examples refer back to the Access Control example and you should be able to see which access control rule each role corresponds to.
Let's say we want to create an admin of a given school, not a global admin, just the admin for a particular school:
user.has_role! :admin, school
user.has_role! :admin, of: schoolThen let's say we have some support people in our organization who are dedicated
to supporting all the schools. We could do two things, either we could come up
with a new role name like :school_support or we can use the fact that we can
assign roles to any object, including a class, and do this:
user.has_role! :support, School
user.has_role! :support, for: SchoolYou can see the allow line in our access_control block that this corresponds
with. If we had used :school_support instead then that line would have to be:
allow :school_support
Now, when a support person leaves that team, we need to remove that role:
user.has_no_role! :support, School
user.has_no_role! :support, at: School
…
sh
bin/rails g acl9:setup -h
…
ruby
user.has_role! :admin, school
…
ruby
# config/initializers/acl9.rb
Acl9.config.default_association_name = :roles
# or...
Acl9.configure do |c|
c.default_association_name = :roles
endOn the off chance that you ever need to reset the config back to its default you can use:
Acl9.config.reset!Please, PLEASE, PLEASE note. If you're upgrading from the 0.x series of acl9
then there's an important change in one of the defaults for 1.x. We flipped
the default value of :protect_global_roles from false to true.
Say you had a role on an object:
user.has_role! :manager, departmentWe all know that this means:
user.has_role? :manager, department # => true
user.has_role? :manager, in: department # => trueWith :protect_global_roles set to false, as it was in 0.x then the above
role would mean that the global :manager role would also be true.
Ie. this is how 0.x behaved:
user.has_role? :manager # => trueNow in 1.x we default :protect_global_roles to true which means that the
global :manager role is protected, ie:
user.has_role? :manager # => falseIn words, in 1.x just because you're the :manager of a department that
doesn't make you a global :manager (anymore).
So basically we downcase, underscore, and singularize your role names, so:
user.has_role! 'FooBars'
user.has_role? 'FooBars' # => true
user.has_role? :foo_bar # => true
user.has_role! :foo_bar # => nil, because it was already set aboveIf you're upgrading then you will want to do something like this:
Role.all.each do |role|
role.update! name: role.name.underscore.singularize
endThen check for any duplicates and resolve those manually.
allow/denyIn 2.x and above we now try to help the developer by raising ArgumentError if
they mess up with the options they pass to allow/deny, this prevents people
doing things that they think are going to work but actually aren't like:
allow all, actions: [ :index, :show ] # <---- BROKEN!!Gitter: Join the gitter chat here
docs: Rdocs are available here.
StackOverflow: Go ask (or answer) a question on StackOverflow
Mailing list: We have an old skule mailing list as well acl9-discuss group
Contributing: Last but not least, check out the Contributing Guide if you want to get even more involved
All these people are awesome! as are all the people who have raised or investigated issues.
No open issues yet, or sync has not completed.