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.