All Projects → rails-engine → Role_core

rails-engine / Role_core

Licence: mit
🔐A Rails engine providing essential industry of Role-based access control.

Programming Languages

ruby
36898 projects - #4 most used programming language

Projects that are alternatives of or similar to Role core

rbac core
(Moved to https://github.com/rails-engine/role_core) A Rails engine providing essential industry of Role-based access control
Stars: ✭ 15 (-94.27%)
Mutual labels:  rails-engine, rbac, access-control
objection-authorize
isomorphic, "magical" authorization integration with Objection.js 🎉
Stars: ✭ 71 (-72.9%)
Mutual labels:  rbac, role, access-control
rbac
RBAC - Simple, concurrent Role Based Access Control(GO)
Stars: ✭ 67 (-74.43%)
Mutual labels:  rbac, role
lua-casbin
An authorization library that supports access control models like ACL, RBAC, ABAC in Lua (OpenResty)
Stars: ✭ 43 (-83.59%)
Mutual labels:  rbac, access-control
sqlx-adapter
Asynchronous casbin adapter for mysql, postgres, sqlite based on sqlx-rs
Stars: ✭ 27 (-89.69%)
Mutual labels:  rbac, access-control
Form core
A Rails engine providing ability to generate dynamic form.
Stars: ✭ 175 (-33.21%)
Mutual labels:  rails-engine, rails
Comfortable Mexican Sofa
ComfortableMexicanSofa is a powerful Ruby on Rails 5.2+ CMS (Content Management System) Engine
Stars: ✭ 2,707 (+933.21%)
Mutual labels:  rails-engine, rails
dart-casbin
An authorization library that supports access control models like ACL, RBAC, ABAC in Dart/Flutter
Stars: ✭ 30 (-88.55%)
Mutual labels:  rbac, access-control
Spotlight
Spotlight enables librarians, curators, and others who are responsible for digital collections to create attractive, feature-rich websites that highlight these collections.
Stars: ✭ 137 (-47.71%)
Mutual labels:  rails-engine, rails
speedle-plus
Speedle+ is an open source project for access management. It is based on Speedle open source project and maintained by previous Speedle maintainers.
Stars: ✭ 45 (-82.82%)
Mutual labels:  rbac, access-control
access-control
Simple, flexible and reliable access control for NodeJS and Typescript. Supports both RBAC and ABAC.
Stars: ✭ 29 (-88.93%)
Mutual labels:  rbac, role
Workflow core
[Deprecated, use flor_core instead] A Rails engine which providing essential infrastructure of workflow. It's based on Workflow Nets.
Stars: ✭ 171 (-34.73%)
Mutual labels:  rails-engine, rails
Flipflop
Flipflop lets you declare and manage feature flags in your Rails application.
Stars: ✭ 165 (-37.02%)
Mutual labels:  rails-engine, rails
rbac-tool
Rapid7 | insightCloudSec | Kubernetes RBAC Power Toys - Visualize, Analyze, Generate & Query
Stars: ✭ 546 (+108.4%)
Mutual labels:  rbac, access-control
Redis web manager
Manage your Redis instance (see keys, memory used, connected client, etc...)
Stars: ✭ 139 (-46.95%)
Mutual labels:  rails-engine, rails
react-abac
Attribute Based Access Control for React
Stars: ✭ 54 (-79.39%)
Mutual labels:  rbac, access-control
Comfy Blog
Blog Engine for ComfortableMexicanSofa (Rails 5.2+)
Stars: ✭ 98 (-62.6%)
Mutual labels:  rails-engine, rails
Rails server timings
Server Timing headers for Rails apps
Stars: ✭ 112 (-57.25%)
Mutual labels:  rails-engine, rails
casbin-ex
An authorization library that supports access control models like ACL, RBAC, ABAC in Elixir
Stars: ✭ 37 (-85.88%)
Mutual labels:  rbac, access-control
Casbin4D
An authorization library that supports access control models like ACL, RBAC, ABAC in Delphi
Stars: ✭ 25 (-90.46%)
Mutual labels:  rbac, access-control

RoleCore

RoleCore is a Rails engine which could provide essential industry of Role-based access control.

Demo

The dummy app shows a simple multiple roles with CanCanCan integration including a management UI.

RoleCore dummy preview

Clone the repository.

$ git clone https://github.com/rails-engine/role_core.git

Change directory

$ cd role_core

Run bundler

$ bundle install

Preparing database

$ bin/rails db:migrate

Start the Rails server

$ bin/rails s

Open your browser, and visit http://localhost:3000

What's does the RoleCore do

The role model

The essence of RBAC is the role, despite your application, there are many possibilities: single-role, multi-roles, extendable-role and the role may associate to different kinds of resources (e.g: users and groups)

RoleCore provides an essential definition of Role, you have to add association to adapt to your application, for example:

  • single-role: adding one-to-many association between Role and User
  • multi-roles: adding many-to-many association between Role and User
  • extendable-role: adding a self-association to Role
  • polymorphic-asscociated-role: consider using polymorphic association technique

Although it's not out-of-box, but it will give you fully flexibility to suit your needs.

Permissions definition

RoleCore provides a DSL (which inspired by Redmine) that allows you define permissions for your application.

Empowered by virtual model technique, these permissions your defined can be persisted through serialization, and can be used with OO-style, for example: role.permissions.project.create?

There also support permission groups, and groups support nesting.

You don't need to any migration when you changing definitions.

I18n is supported too.

In fact, the essence of permissions is Hash, keys are permissions, and values are booleans. so computing of permissions with many roles, can be understood as computing of Hashes.

Management UI

Building a management UI is difficult, but virtual model technique will translates permissions to a virtual model's (a class that conforms to ActiveModel) attributes, and groups will translates to nested virtual models, that means you can use all Rails view helpers including the mighty form builder, and can benefit to Strong Parameter.

The dummy app shows that rendering a permission list only about 20 lines.

If your application is API-only, you can simply dumping the role's permissions to JSON, and can still be benefit to StrongParameter.

Checking permission

RoleCore DOES NOT handle the authentication or authorization directly, you have to integrate with CanCanCan, Pundit or other solutions by yourself.

RoleCore can be working with CanCanCan, Pundit easily and happily.

Installation

Add this line to your Gemfile:

gem 'role_core'

Then execute:

$ bundle

Copy migrations

$ bin/rails role_core:install:migrations

Then do migrate

$ bin/rails db:migrate

Run config generator

$ bin/rails g role_core:config

Run model generator

$ bin/rails g role_core:model

Getting start

Define permissions

Permissions are defined in config/initializers/role_core.rb, checking it to know how to define permissions.

In addition, there also includes a directive about how to integrate with CanCanCan.

I18n

Check config/locales/role_core.en.yml

Hook application

In order to obtain maximum customizability, you need to hooking up role(s) to your user model by yourself.

User who has single role

Create one-to-many relationship between Role and User

Generate one-to-many migration, adding role_id to User model

$ bin/rails g migration AddRoleToUsers role:references

Then do migrate

$ bin/rails db:migrate

Declare a User belongs to a Role association

class User < ApplicationRecord
  belongs_to :role

  # ...
end

Declare a Role has many Users association

class Role < RoleCore::Role
  has_many :users
end
Checking permission

Permissions you've defined will translate to a virtual model (a Class which implemented ActiveModel interface), permission would be an attribute, group would be a nested virtual model (like ActiveRecord's has_one association).

So you can simply check permission like:

user.role.permissions.read_public?
user.role.permissions.project.read? # `project` is a `group`

For better usage, you may delegate the permissions from Role model to User:

class User < ApplicationRecord
  belongs_to :role

  delegate :permissions, to: :role

  # ...
end

Then you can

user.permissions.read_public?
user.permissions.project.read?

Keep in mind: fetching role will made a SQL query, you may need eager loading to avoid N+1 problem in some cases.

User who has multiple roles

Create many-to-many relationship between Role and User

Generate a many-to-many intervening model

$ bin/rails g model RoleAssignment user:references role:references

Then do migrate

$ bin/rails db:migrate

Declare a User has many Roles through RoleAssignments association

class User < ApplicationRecord
  has_many :role_assignments, dependent: :destroy
  has_many :roles, through: :role_assignments

  # ...
end

Declare a Role has many Users through RoleAssignments association

class Role < RoleCore::Role
  has_many :role_assignments, dependent: :destroy
  has_many :users, through: :role_assignments
end
Check permission

Permissions you've defined will translate to a virtual model (a Class which implemented ActiveModel interface), permission would be an attribute, group would be a nested virtual model (like ActiveRecord's has_one association).

So you can simply check permission like:

user.roles.any? { |role| role.permissions.read_public? }
user.roles.any? { |role| role.permissions.project.read? } # `project` is a `group`

For better usage, you could declare a can? helper method:

class User < ApplicationRecord
  has_many :role_assignments, dependent: :destroy
  has_many :roles, through: :role_assignments

  def can?(&block)
    roles.map(&:permissions).any?(&block)
  end

  # ...
end

Then you can

user.can? { |permissions| permissions.read_public? }
user.can? { |permissions| permissions.project.read? }

Keep in mind: fetching roles will made a SQL query, you may need eager loading to avoid N+1 problem in some cases.

Integrate with Pundit

Just call permissions' method (see checking permission above) in Pundit's policy.

e.g:

class PostPolicy
  attr_reader :user, :post

  def initialize(user, post)
    @user = user
    @post = post
  end

  def update?
    user.permissions.post.update?
  end

  def update_my_own?
    return true if user.permissions.post.update?
    return unless user.permissions.post.update_my_own?
    post.author == user
  end
end

Integrate with CanCanCan

Open config/initializers/role_core.rb, uncomment CanCanCan integration codes and follows samples to define permissions for CanCanCan

Open your User model:

  • For a user who has single role:

    Add a delegate to User model:

    delegate :computed_permissions, to: :role
    
  • For a user who has multiple roles:

    Add a computed_permissions public method to User model:

    def computed_permissions
      roles.map(&:computed_permissions).reduce(RoleCore::ComputedPermissions.new, &:concat)
    end
    

Open app/models/ability.rb, add user.computed_permissions.call(self, user) to initialize method.

class Ability
  include CanCan::Ability

  def initialize(user)
    # Apply RoleCole managing permissions
    user.computed_permissions.call(self, user)

    # You still can add other permissions
    can :read_public, :all
  end
end

You can check dummy app for better understanding.

Management UI

See RolesController in dummy app and relates view for details.

Hacking

RoleCore is a Rails engine, and following the official best practice, so you can extend RoleCore by the article suggests.

Integrate to existing role model

For some reason, you want to use RoleCore's ability and keeping use your own role model, e.g: integrate with rolify.

You can archive this goal by:

  • Modify the migration file which RoleCore generated, changing the role table name
  • Add include RoleCore::Concerns::Models::Role to your role model

Note: If you want another column name or there's no name in your role model, you need to lookup RoleCore::Concerns::Models::Role source code, copy and modify to fit your needs

Dynamic permissions

By design, RoleCore is for static permissions, but dynamic permissions is easy to support.

The key is RoleCore::PermissionSet#derive, that will generate a new anonymous sub-class of PermissionSet.

Here's an example:

  • Design a model to persisting dynamic permissions, e.g DynamicPermission(id: bigint, name: string, default: bool)
  • Add dynamic_permissions column (text type) to Role model to persisting dynamic permissions' configuration, and in your model serialize :dynamic_permissions, Hash
  • Generate dynamic permissions set in runtime
    # Create a new permission set to containerize dynamic permissions
    # `"Dynamic"` can be named to other but must be a valid Ruby class name,
    # that's a hacking for `ActiveModel::Naming`,
    # and can be used as I18n key, in this case, the key is `role_core/models/dynamic`.
    dynamic_permission_set_class = PermissionSet.derive "Dynamic"
    
    # Fetching dynamic permissions
    dynamic_permissions = DynamicPermission.all
    
    # Mapping dynamic permissions to permission set
    dynamic_permission_set_class.draw do
      dynamic_permissions.each do |p|
        permission p.name, default: p.default
      end
    end
    
  • Create a instance of this dynamic permission set
    dynamic_permissions = dynamic_permission_set_class.new(role.dynamic_permissions)
    
  • You can use the dynamic_permissions now

Rails' serialize is static so you must do serialize and deserialize manually, you can wrap these logic into model.

Contributing

Bug report or pull request are welcome.

Make a pull request

  1. Fork it
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create new Pull Request

Please write unit test with your code if necessary.

License

The gem is available as open source under the terms of the MIT License.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].