Cancan & Rolify Gems

 

Ruby on Rails

Temas:

  • Conceptos: Authentication & Authorization
  • Rolify
  • Cancan
  • Cancancan
  • Demo
  • Análisis

Authentication

Verificar la Identidad del Usuario.

Authorization

Establecer que acciones puede realizar un usuario autenticado.

Conceptos:

Rolify

Cancan

Rolify

Rolify es una gema que permite asociar roles a los usuarios. Ofrece un generador para un modelo de roles, y también algunos métodos que vincula a sus modelos y usuarios

# Gemfile
gem 'rolify'

# bash
bundle install

Instalación

Documentación: https://github.com/RolifyCommunity/rolify

Generar Roles

Generar la clase Role

# bash
rails generate rolify Role User
# db/migrate/20150109121250_rolify_create_roles
class RolifyCreateRoles < ActiveRecord::Migration
  def change
    create_table(:roles) do |t|
      t.string :name
      t.references :resource, :polymorphic => true

      t.timestamps
    end

    create_table(:users_roles, :id => false) do |t|
      t.references :user
      t.references :role
    end

    add_index(:roles, :name)
    add_index(:roles, [ :name, :resource_type, :resource_id ])
    add_index(:users_roles, [ :user_id, :role_id ])
  end
end

Migración

# bash
rake db:migrate

Correr Migración

En vez de User puede ser cualquier modelo

Modelos

# app/models/role.rb
class Role < ActiveRecord::Base
  has_and_belongs_to_many :users, :join_table => :users_roles
  belongs_to :resource, :polymorphic => true

  #validates :resource_type, :inclusion => { :in => Rolify.resource_types }

  scopify
end

Clase Role

Clase User

# app/models/user.rb
class User < ActiveRecord::Base
  rolify

end

Clase a la cual queremos asociar un rol

creada por el generador de rolify

Configuraciones

Clase Article (clase que queremos manejar a través de un rol)

# app/models/article.rb
class Article < ActiveRecord::Base
	resourcify
end

Para mayor información: https://github.com/ryanb/cancan/wiki/Controller-Authorization-Example

Poner resourcify en los modelos en los cuales se desea aplicar roles

Configuraciones

Controlador User

# app/controllers/users_controller.rb
def create
    @user = User.new(user_params)
    add_roles(@user)

    if @user.save
      redirect_to root_url, :notice => "sign_up!"
    else
        render "new"
    end
end

private
  def add_roles(resource)
    resource.roles = []
    unless params[:user][:role_ids].blank?
      params[:user][:role_ids].each do |role|
        resource.add_role Role.find(role).name
      end
    end
end
# app/views/users/new.html.erb
<% @roles.each do |role| %>
     <%= check_box_tag "user[role_ids][]", role.id %>
     <%= role.name %>
<% end -%>

Vista User

No existe un add_roles method por default

CanCan

Cancan es una gema que provee un mecanismo de control de acceso que se conecta a los controladores, y comprueba si los usuarios han tenido acceso a las operaciones que están tratando de realizar.

# Gemfile
gem 'cancan'

# bash
bundle install

Instalación

Documentación: https://github.com/ryanb/cancan

Generar Ability

Capacidad

  • En la clase Ability se definen todos los métodos y modelos a los cuales cada usuario puede acceder.
# bash
rails generate cancan:ability

Crea la clase Ability

# app/models/ability
class Ability
  include CanCan::Ability

  def initialize(user)

  end
end

Configuraciones

# app/models/ability
class Ability
  include CanCan::Ability

  def initialize(user)

    user ||= User.new # guest user (not logged in)

    if user.has_role? :admin
        can :manage, :all
    end
    if user.has_role? :moderator
        can :edit, Article
    end
    
    # all users can ...
    can :read, Article
    can :create, User
end
# format
can :method, model

Clase Ability

Formato

Controlador Article

# app/controllers/articles_controller
class ArticlesController < ApplicationController

  load_and_authorize_resource

  def method
    ...
  end

end

load_and_authorize_resource

es un "before_filter"

Establece un filtro antes de cada acción/método para manejar la carga y la autorización del Controlador

# app/controllers/articles_controller.rb
class ArticlesController < ApplicationController

    def show
      @article = Article.find(params[:id])
      authorize! :read, @article, :message => "Unable to read this article."
    end

end

Configuraciones

Controlador Article

El método authorize! permite manejar la autorización manualmente en cada acción. Esto lanzará una excepción CanCan::AccessDenied cuando un usuario sin permisos intente acceder a esa acción.

# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  rescue_from CanCan::AccessDenied do |exception|
    redirect_to root_url, :alert => exception.message
  end
end

Configuraciones: 

ActionController

Manejar excepción de accesos no autorizados.

https://github.com/CanCanCommunity/cancancan/wiki/exception-handling

#app/views/articles/index.html.rb

<% @articles.each do |article| %>
  <tr>
     <td><%= article.title %></td>
     <td><%= article.description %></td>
     <td><%= link_to 'Show', article %></td>
     <% if can? :edit, article%>
       <td><%= link_to 'Edit', edit_article_path(article) %></td>
     <% end -%>
     <% if can? :destroy, article %>
       <td><%= link_to 'Destroy', article, method: :delete, data: { confirm: 'Are you sure?' } %></td>
     <% end -%>
  </tr>
<% end %>

Vista

Configuraciones

Cancan en Rails4?

http://www.ready4rails4.net/

Porqué cancan no soporta Rails4?

http://blog.houen.net/cancan-strong-parameters/

CanCanCan

Cancancan es una gema que continua el proyecto cancan, maneja los problemas de la antigua versión con strong parameters de rails4.

# Gemfile
gem 'cancancan'

# bash
bundle install

Instalación

Documentación: https://github.com/CanCanCommunity/cancancan

Convención!

https://github.com/CanCanCommunity/cancancan/wiki/Strong-Parameters

Por default, CanCanCan tratará de sanitizar los inputs con rutas referentes a create y update viendo si el controlador responde a uno de los determinados métodos:

  • create_params o update_params 
    • (dependiendo de la acción que se esté ejecutando)
  • <model_name>_params
    •  como por ejemplo article_params (esta es la convención por default en rails para nombrar param methods)
  • resource_params 
    • (un nombre de método genérico que se puede especificar en cada modelo)

Strong Parameters

Rails 3 o anterior

Rails 4

#ruby

#params = {article: {title: "Da vinci code}}
@article = Article.create(params[:article])

Cualquier usuario puede realizar las acciones create y update con la url.

#ruby

#params = {article: {title: "Da vinci code}}

def create
    @article = Article.new(article_params)
    ...
end

def article_params
      params.require(:article).permit(:title, :description)
end

Hay que "sanitizar" los parámetros  antes de guardarlos.

Recursos

https://groups.google.com/forum/#!forum/cancancan

https://github.com/CanCanCommunity/cancancan/issues

google group

Issues

Demo

https://github.com/sespinozj/rolify_cancancan

Análisis

Ruby on Rails: Cancan & Rolify Gem

By Sam W

Ruby on Rails: Cancan & Rolify Gem

Description and usage of the gem

  • 1,935