\chapter{Authentification}

Comme on l'a vu dans la partie sur le modèle, nous souhaitons que le créateur d'une liste puisse retrouver facilement les éléments qu'il aura créée. 
Ce dont nous n'avons pas parlé cependant, c'est la manière dont l'utilisateur va pouvoir créer son compte et s'authentifier. 
La \href{https://docs.djangoproject.com/en/stable/topics/auth/}{documentation} est très complète, nous allons essayer de la simplifier au maximum.
Accrochez-vous, le sujet peut être complexe.

\section{Utilisateurs}

Dans les spécifications, nous souhaitions pouvoir associer un utilisateur à une liste (\textbf{le propriétaire}) et un utilisateur à une part (\textbf{le donateur}). 
Par défaut, Django offre une gestion simplifiée des utilisateurs (pas de connexion LDAP, pas de double
authentification, ...: juste un utilisateur et un mot de passe. 
Pour y accéder, un paramètre par défaut est défini dans votre fichier de settings: \texttt{AUTH\_USER\_MODEL}.

\section{Mécanisme d'authentification}

On peut schématiser le flux d'authentification de la manière suivante :

En gros:

\begin{enumerate}
\item
  La personne accède à une URL qui est protégée (voir les décorateurs @login\_required et le mixin LoginRequiredMixin)
\item
  Le framework détecte qu'il est nécessaire pour la personne de se connecter (grâce à un paramètre type LOGIN\_URL)
\item
  Le framework présente une page de connexion ou un mécanisme d'accès pour la personne (template à définir)
\item
  Le framework récupère les informations du formulaire, et les transmets aux différents backends d'authentification, dans l'ordre
\item
  Chaque backend va appliquer la méthode \texttt{authenticate} en cascade, jusqu'à ce qu'un backend réponde True ou qu'aucun ne réponde
\item
  La réponse de la méthode authenticate doit être une instance d'un utilisateur, tel que définit parmi les paramètres généraux de l'application.
\end{enumerate}

En résumé (bis):

\begin{enumerate}
\item
  Une personne souhaite se connecter;
\item
  Les backends d'authentification s'enchaîne jusqu'à trouver une bonne
  correspondance. Si aucune correspondance n'est trouvée, on envoie la
  personne sur les roses.
\item
  Si OK, on retourne une instance de type current\_user, qui pourra être
  utilisée de manière uniforme dans l'application.
\end{enumerate}

Ci-dessous, on définit deux backends différents pour mieux comprendre
les différentes possibilités:

\begin{enumerate}
\item
  Une authentification par jeton
\item
  Une authentification LDAP
\end{enumerate}

\begin{minted}{python}
from datetime import datetime

from django.contrib.auth import backends, get_user_model
from django.db.models import Q

from accounts.models import Token

UserModel = get_user_model()

class TokenBackend(backends.ModelBackend):
    def authenticate(self, request, username=None, password=None, **kwargs):
    """Authentifie l'utilisateur sur base d'un jeton qu'il a reçu.
    On regarde la date de validité de chaque jeton avant d'autoriser
    l'accès.
    """
        token = kwargs.get("token", None)
        current_token = Token.objects.filter(
            token=token, validity_date__gte=datetime.now()
        ).first()
        
        if current_token:
            user = current_token.user
            current_token.last_used_date = datetime.now()
            current_token.save()
    
        return user
    
    return None
\end{minted}