Recommend Me


Mercredi 2 juillet 2008

before_filter dans Bivouac

Classé dans : Camping, Projets, Ruby, bivouac — greg @ 19:13

Le développement de la version 0.3.0 de Bivouac avance…

Pour le moment, j’ai modifié le script plugin afin de permettre de récupérer les plugins sur une machine n’ayant pas de client SVN installé. Pour cela j’ai mis en place une méthode de récupération via HTTP.

J’ai également corrigé le générateur qui plaçait le fichier de configuration console.rc au mauvais endroit.

Enfin, j’ai ajouté before_filter. Voici un petit exemple d’utilisation avec la mise en place d’un système d’authentification.

Commençons pas créer une nouvelle application :

$ bivouac test

Ajoutons un modèle User

$ ruby script/generate model User login:string password_salt:string password_hash:string
        create /Users/greg/temp/test_filters/app/models/user.rb
        create /Users/greg/temp/test_filters/db/migrate/001_user.rb
        create /Users/greg/temp/test_filters/db/create.rb

Modifions le fichier app/models/user.rb comme ceci :

require ‘digest/sha2′

module TestFilter::Models
  class User < Base
    def password=(pass)
      salt = [Array.new(6){rand(256).chr}.join].pack("m").chomp
      self.password_salt, self.password_hash = salt, Digest::SHA256.hexdigest( pass + salt )
    end
   
    def self.authenticate( login, password )
      user = User.find_by_login( login )
      if user.blank? || Digest::SHA256.hexdigest( password + user.password_salt ) != user.password_hash
        return nil
      end
      user
    end
  end
end

Nous pouvons dès à présent ajouter un utilisateur dans notre base via la console :

$ ruby script/console  
>> u = User.new
=> #<TestFilter::Models::User id: nil, login: nil, password_salt: nil, password_hash: nil>
>> u.login = "greg"
=> "greg"
>> u.password = "motdepasse"
=> "glatvd"
>> u.save
=> true
>> u = User.find( :all )
=> [#<TestFilter::Models::User id: 1, login: "greg", password_salt: "K6cXb1Om", password_hash: "25233354623a362a303091683a9d4229a72b0a7906293da388b...">]
=> ^D

Ajoutons un controller Admin avec trois actions (login, logout et home) :

$ ruby script/generate controller admin login logout home
        create /Users/greg/temp/test_filters/app/views/admin
        create /Users/greg/temp/test_filters/app/controllers/admin.rb
        create /Users/greg/temp/test_filters/app/views/admin/login.rb
        create /Users/greg/temp/test_filters/app/views/admin/logout.rb
        create /Users/greg/temp/test_filters/app/views/admin/home.rb
        create /Users/greg/temp/test_filters/test/test_admin.rb

Dans la vue app/views/admin/login.rb nous devons mettre en place un formulaire pour la saisie du login et du mot de passe :

module TestFilter::Views
  def admin_login
    unless @error.nil?
      div do
        b @error
      end
    end
     
    form_tag R(AdminLogin) do
      p do
        text "Identifiant : "; br; input :type => "text", :name => "login"
      end
      p do
        text "Mot de passe : "; br; input :type => "password", :name => "password"
      end
      p { input :type => "submit", :value => "Entrer" }
    end
  end
end

La vue app/views/admin/home.rb sera notre page d’administration principale. Nous n’allons rien y mettre de pertinent pour cet exemple à par un lien vers la page de déconnexion :

a "Logout", :href => R(AdminLogout)

Nous n’avons pas besoin de la vue app/views/admin/logout.rb. En effet, quand l’utilisateur demande à se déconnecter il est immédiatement redirigé vers la page de login.

Passons à ma modification du contoller app/controllers/admin.rb. Les parties login, logout et home sont “classiques” :

module TestFilter::Controllers
  class AdminLogin < R ‘/admin/login’
    def get
      if @state[:user].blank?
        @error = nil
        render :admin_login
      else
        redirect R(AdminHome)
      end
    end
    def post
      user = User.authenticate( input.login, input.password )
      if user.nil?
        @error = "Login ou mot de passe incorrect…"
        render :admin_login
      else
        @state[:user] = user.id
        if @state[:redirect].blank?
          redirect R(AdminHome)
        else
          redirect @state[:redirect]
        end
      end      
    end
  end
 
  class AdminLogout < R ‘/admin/logout’
    def get
      @state[:user] = nil
      redirect AdminLogin
    end
   
    alias :post :get
  end
 
  class AdminHome < R ‘/admin/home’
    def get
      render :admin_home
    end
    def post
      render :admin_home
    end
  end
end

Comme vous pouvez le voir, nous stockons dans la session un paramètre :user qui, s’il existe, contient l’ID de l’utilisateur authentifié.

Ce qui nous manque ici, c’est un filtre pour détecter que l’utilisateur est bien identifié quand il arrive sur . Et c’est là que nous utilisons le fameux before_filter.

La première chose que nous allons faire c’est donc de rajouter un filtre dans notre controller :

module TestFilter::Controllers

  # …

  class AdminCheckLogin
    def self.filter( state )
      if state[:user].blank?
        return AdminLogin
      else
        return nil
      end
    end
  end
end

La classe AdminCheckLogin contient notre filtre déclaré via la méthode de classe filter. Cette méthode prend un paramètre correspondant aux données de sessions. Nous vérifions s’il y a bien un user pour la session courante, ci c’est le cas nous renvoyons nil sinon nous renvoyons le classe du controller vers laquelle rediriger l’utilisateur (ici AdminLogin).

Il ne reste plus qu’a déclarer ce filtre. Pour cela nous ajoutons la ligne suivante après la déclaration de la classe AdminCheckLogin :

before_filter AdminCheckLogin, :only => [AdminHome]

Comme vous pouvez le voir, before_filter prend en premier paramètre le nom de la classe de filter et en second un hashage précisant les conditions d’application du filtre.

Faites bien attention. Contrairement à Rails, before_filter utilise des noms de classes et non des symboles. Il est donc important de placer ses filtres en fin de controller avec le before_filter en dernière ligne.

Si vous voulez bénéficier de ces amélioration tout de suite, vous pouvez récupérer les sources.

• • •

Un commentaire »

  1. [...] un article précédent, je vous avais montré comment utiliser before_filter dans Bivouac. before_filter ayant été remplacé, dans la dernière [...]

    Ping par greg.rubyfr.net»Blog Archive » Utiliser before à la place de before_filter dans Bivouac — Mardi 16 décembre 2008 @ 12:16

RSS des commentairesTrackBack URI

Laisser un commentaire

You must be logged in to post a comment.

Powered by: WordPress • Template adapted from the Simple Green' Wench theme - RSS