Avec rails comme avec tout framework, vous allez rapidement avoir besoin de gérer l’identification des utilisateurs et leurs autorisations.
Pour leur identification, il existe divers plugins. Notamment Restful Authentication, AuthLogic et (mon préféré) Clearance.
Pour la gestion des autorisations, je vais vous parler de ACL9.
L’idée est simple. Après avoir identifié votre utilisateur, vous avez accès à un objet current_user, qui contient l’objet relatif à l’utilisateur actif (généralement une instance du model User. Mais cela peut être n’importe quoi).
ACL9 va ajouter deux tables :
- Role, qui contiendra tous les rôles utilisateurs existants. Un peu comme des groupes. Chaque rôle pouvant être associé à une instance d’un objet.
Vous pourrez ainsi avoir un rôle « admin », global, qui permettra de définir les accès de l’administrateur.
Et un rôle « éditeur », relatif uniquement à l’objet ayant pour id « 1″ du modèle « News ».
- UserRole, qui fera la relation entre un rôle et un utilisateur (has_and_belongs_to_many).
Voici les migrations nécessaires pour ces deux tables :
create_table :roles, :force => true do |t|
t.column :name, :string, :limit => 40
t.column :authorizable_type", :string, :limit => 40
t.column :authorizable_id, :integer
t.timestamps
end
create_table :roles_users", :id => false, :force => true do |t|
t.column :user_id, :integer
t.integer :role_id, :integer
t.timestamps
end
Vous devez bien évidemment créer un modèle « Role », qui représentera cette table. Il est inutile de créer un modèle RolesUser. Cela sera géré automatiquement par Rails.
class Role < ActiveRecord::Base
acts_as_authorization_role
end
Vous noterez l’ajout de « acts_as_authorization_role », qui va implémenter les méthodes de rôles relatives à ACL9.
Dans notre table user, nous allons également devoir ajouter un appel à une méthode spécifique de ACL9 afin d’ajouter les méthodes relatives à l’utilisateur.
class User < ActiveRecord::Base
acts_as_authorization_subject
end
Et dans tous les modèles ou nous désirons avoir une gestion des droits d’accès, nous allons ajouter :
class Foo < ActiveRecord::Base
acts_as_authorization_object
end
ACL9 vous a maintenant ajouté diveres méthodes dans vos objets :
Dans votre modèle utilisateur :
- has_role?(role, object = nil) – Retournera « true » si l’utilisateur a le rôle demandé en global ou sur l’objet précisé.
- has_role!(role, object = nil) – Donnera le rôle nommé à l’utilisateur
- has_no_role!(role, object = nil) – Supprimera le rôle nommé pour l’utilisateur
- has_roles_for?(object) – Retourne true si l’utilisateur a un quelconque rôle sur l’objet
- has_role_for?(object) – Alias de has_roles_for?
- roles_for(object) – Retourne tous les rôles de l’utilisateur pour cet objet
- has_no_roles_for!(object) – Supprime tous les rôles de l’utilisateur pour l’objet
- has_no_roles! – Supprime tous les rôles de l’utilisateur
Et dans chacun de vos modèles objets (Foo plus haut) :
- accepts_role?(role, subject) – Retourne true si subject a accès au rôle courant
- accepts_role!(role, subject) – Donne accès à subject au rôle courant
- accepts_no_role!(role, subject) – Supprime l’accès utilisateur au rôle
- accepts_roles_by?(subject) – Retourne true si l’utilisateur a un rôle quelconque sur l’objet
- accepts_role_by?(subject) – Alias de accepts_roles_by?
- accepted_roles_by(subject) – Retourne tous les utilisateurs ayant un rôle pour cet objet
Maintenant que nous avons implémenté nos autorisations et que nous avons vu les diverses méthodes pour les utiliser, limitons les accès à nos actions !
class MyOwnController < ApplicationController
access_control do
# Autorise tous les utilisateurs ayant le rôle "superadmin" à accéder à l'objet
allow :superadmin
# Autorise tous les utilisateurs ayant le rôle "creator" sur @news
allow :creator, :at => :news
# Autorise les utilisateurs anonymes et ceux qui sont enregistrés sur la page d'accueil
# Et refuse les utilisateurs ayant le rôle "banned"
action :index do
allow anonymous, logged_in
deny :banned
end
# Autorise les utilisateurs ayant le rôle "manager" sur l'objet @news. Sauf pour l'action "destroy"
allow :manager, :at => :news, :except => [:destroy]
end
def index
@news = News.find_by_id params[:id]
# Le code relatif à l'action "index"
end
end
Du coup on peut maintenant gérer de manière particulièrement avancée les rôles dans notre application.