Pourquoi Authentification dans Rails ?
L'authentification est un élément fondamental de tout site Web ou application mobile moderne. Elle permet de gérer les utilisateurs, de protéger leurs données et d'assurer la sécurité des interactions entre l'utilisateur et le système. Dans un contexte professionnel, une authentification robuste est essentielle pour maintenir la confiance des utilisateurs dans votre application.
Un cas concret serait un site de gestion de projet où les utilisateurs doivent être en mesure de s'authentifier pour consulter leurs tâches et collaborer avec d'autres membres du projet. Sans authentification, le risque est élevé que toutes les données soient accessibles à tout le monde, ce qui entraînerait des problèmes majeurs en termes de sécurité et de confidentialité.
Prerequis
- Connaissance avancée de Ruby on Rails
- Familiarité avec les bases de données SQL (PostgreSQL, MySQL)
- Connaissance des concepts de modèles, de contrôleurs et de vues
- Compréhension des routes et des formulaires HTML
- Installation de Ruby 3.x et Rails 7.x
- Utilisation d'un éditeur de code comme VSCode ou Sublime Text
Concepts fondamentaux
Modèle User
Le modèle User est le cœur de l'authentification. Il doit contenir les champs nécessaires pour stocker les informations de l'utilisateur, comme son nom d'utilisateur, son mot de passe et sa confirmation.
## app/models/user.rb
class User < ApplicationRecord
# Valide la présence du nom d'utilisateur et du mot de passe
validates :username, presence: true, uniqueness: true
validates :password, presence: true, length: { minimum: 6 }
# Hashage du mot de passe avant de l'enregistrer dans la base de données
has_secure_password
end
Contrôleur Sessions
Le contrôleur Sessions gère les actions liées à l'authentification. Il inclut des méthodes pour créer une session (login) et détruire une session (logout).
## app/controllers/sessions_controller.rb
class SessionsController < ApplicationController
def new
# Affiche le formulaire de connexion
end
def create
user = User.find_by(username: params[:session][:username])
if user && user.authenticate(params[:session][:password])
log_in user
flash[:success] = "Connecté avec succès !"
redirect_to root_path
else
flash.now[:danger] = "Nom d'utilisateur ou mot de passe incorrect."
render 'new'
end
end
def destroy
log_out if logged_in?
flash[:success] = "Déconnecté avec succès !"
redirect_to login_path
end
end
Formulaires HTML
Le formulaire HTML pour l'authentification est simple et utilise la méthode POST pour envoyer les données au contrôleur.
<!-- app/views/sessions/new.html.erb -->
<h1>Connexion</h1>
<%= form_with url: login_path, method: :post do |f| %>
<%= f.label :username %>
<%= f.text_field :username %>
<%= f.label :password %>
<%= f.password_field :password %>
<%= f.submit "Se connecter" %>
<% end %>
Middleware et Helper Methods
Rails fournit des middleware et des helper methods pour gérer les sessions. Le middleware ActionDispatch::Session::CookieStore stocke la session dans un cookie.
## config/initializers/session_store.rb
Rails.application.config.session_store :cookie_store, key: '_my_app_session'
Les helper methods logged_in?, current_user et log_in sont définis dans le fichier application_controller.rb.
## app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
# Méthode pour vérifier si un utilisateur est connecté
def logged_in?
!current_user.nil?
end
# Méthode pour récupérer l'utilisateur actuellement connecté
def current_user
@current_user ||= User.find_by(id: session[:user_id])
end
# Méthode pour connecter un utilisateur
def log_in(user)
session[:user_id] = user.id
end
# Méthode pour déconnecter un utilisateur
def log_out
session.delete(:user_id)
@current_user = nil
end
end
Mise en pratique : projet fil rouge
Étape 1 : Création du modèle User
rails generate model User username:string password_digest:string
rake db:migrate
Étape 2 : Création du contrôleur Sessions
rails generate controller Sessions new create destroy
Étape 3 : Configuration des routes
Ajoutez les routes dans config/routes.rb :
Rails.application.routes.draw do
root 'tasks#index'
resources :tasks
get '/login', to: 'sessions#new'
post '/login', to: 'sessions#create'
delete '/logout', to: 'sessions#destroy'
resources :users, only: [:new, :create]
end
Étape 4 : Création du modèle Task
rails generate model Task title:string description:text user_id:integer completed:boolean
rake db:migrate
Étape 5 : Configuration des associations
Modifier les modèles User et Task pour ajouter des associations :
## app/models/user.rb
class User < ApplicationRecord
has_secure_password
has_many :tasks
end
## app/models/task.rb
class Task < ApplicationRecord
belongs_to :user
end
Étape 6 : Création de la vue des tâches
Créez une vue index pour afficher les tâches :
<!-- app/views/tasks/index.html.erb -->
<h1>Mes Tâches</h1>
<% if logged_in? %>
<%= link_to 'Nouvelle tâche', new_task_path %>
<% else %>
<p>Veuillez vous connecter pour voir vos tâches.</p>
<% end %>
<ul>
<% @tasks.each do |task| %>
<li><%= task.title %> - <%= task.description %></li>
<% end %>
</ul>
Étape 7 : Création de la vue des formulaires
Créez une vue new pour ajouter une nouvelle tâche :
<!-- app/views/tasks/new.html.erb -->
<h1>Nouvelle Tâche</h1>
<%= form_with model: @task do |f| %>
<%= f.label :title %>
<%= f.text_field :title %>
<%= f.label :description %>
<%= f.text_area :description %>
<%= f.submit "Ajouter tâche" %>
<% end %>
Étape 8 : Configuration des helper methods
Modifiez application_controller.rb pour inclure les helper methods :
class ApplicationController < ActionController::Base
before_action :require_login, except: [:new, :create]
private
def require_login
unless logged_in?
flash[:danger] = "Vous devez être connecté pour accéder à cette page."
redirect_to login_path
end
end
end
Erreurs frequentes et debugging
Erreur 1 : ActiveRecord::RecordInvalid
## ❌ Mauvais
user = User.create(username: params[:session][:username], password: params[:session][:password])
rails
## ✅ Correct
if user.save
log_in user
else
render 'new'
end
Erreur 2 : NoMethodError: undefined method 'authenticate' for nil:NilClass
## ❌ Mauvais
user = User.find_by(username: params[:session][:username])
if user && user.authenticate(params[:session][:password])
log_in user
else
flash.now[:danger] = "Nom d'utilisateur ou mot de passe incorrect."
render 'new'
end
rails
## ✅ Correct
user = User.find_by(username: params[:session][:username])
if user&.authenticate(params[:session][:password])
log_in user
else
flash.now[:danger] = "Nom d'utilisateur ou mot de passe incorrect."
render 'new'
end
Erreur 3 : ActionDispatch::Cookies::CookieOverflowError
## ❌ Mauvais
user_id = session[:user_id]
session.delete(:user_id)
rails
## ✅ Correct
if user_id = session[:user_id]
session.delete(:user_id)
end
Pour aller plus loin
OAuth et Authentification sociale : Ajoutez l'authentification avec des comptes Google, Facebook ou Twitter pour permettre aux utilisateurs de s'inscrire facilement.
JWT (JSON Web Tokens) : Utilisez JWT pour gérer les tokens d'authentification plutôt que des sessions cookies. Cela offre une meilleure sécurité et flexibilité.
Pampered Chef : Intégrez un système de gestion de mots de passe plus sécurisé en utilisant le gem Pampered Chef.
Défi pratique
Ajoutez une fonctionnalité pour les utilisateurs de modifier leurs mots de passe. Créez un formulaire de changement de mot de passe et mettez à jour la méthode update dans le contrôleur UsersController.
<!-- app/views/users/edit.html.erb -->
<h1>Modifier mon mot de passe</h1>
<%= form_with model: current_user do |f| %>
<%= f.label :current_password %>
<%= f.password_field :current_password, autocomplete: "current-password" %>
<%= f.label :new_password %>
<%= f.password_field :password, autocomplete: "new-password" %>
<%= f.label :new_password_confirmation %>
<%= f.password_field :password_confirmation, autocomplete: "new-password-confirm" %>
<%= f.submit "Mettre à jour mon mot de passe" %>
<% end %>
ruby
## app/controllers/users_controller.rb
class UsersController < ApplicationController
def edit
@user = current_user
end
def update
@user = current_user
if @user.update(user_params)
flash[:success] = "Mot de passe mis à jour avec succès !"
redirect_to root_path
else
render 'edit'
end
end
private
def user_params
params.require(:user).permit(:password, :password_confirmation)
end
end
Conclusion
Cette mise en pratique complète vous permet de comprendre la structure et les concepts essentiels de l'authentification dans Rails. En suivant ces étapes, vous devriez être capable de mettre en œuvre une authentification robuste pour n'importe quel projet Rails. N'oubliez pas de tester soigneusement votre application pour vous assurer qu'elle fonctionne comme prévu et est sécurisée contre les menaces courantes.