Merge branch 'master' of grimbox.be:fred/gwift-book

This commit is contained in:
Fred 2020-04-04 21:48:03 +02:00
commit a88c816fb8
2 changed files with 121 additions and 1 deletions

View File

@ -8,6 +8,98 @@ Comme on l'a vu dans la partie sur le modèle, nous souhaitons que le créateur
Mécanisme d'authentification
****************************
On peut schématiser le flux d'authentification de la manière suivante :
En gros:
. La personne accède à une URL qui est protégée (voir les décorateurs @login_required et le mixin LoginRequiredMixin)
. Le framework détecte qu'il est nécessaire pour la personne de se connecter (grâce à un paramètre type LOGIN_URL)
. Le framework présente une page de connexion ou un mécanisme d'accès pour la personne (template à définir)
. Le framework récupère les informations du formulaire, et les transmets aux différents backends d'authentification, dans l'ordre
. Chaque backend va appliquer la méthode `authenticate` en cascade, jusqu'à ce qu'un backend réponde True ou qu'aucun ne réponde
. 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.
En résumé (bis):
. Une personne souhaite se connecter;
. 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.
. Si OK, on retourne une instance de type curren_user, qui pourra être utilisée de manière uniforme dans l'application.
Deux exemples :
. Une authentification par jeton
. Une authentification LDAP
[source,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 <1>
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
----
<1> Sous-entend qu'on a bien une classe qui permet d'accéder à ces jetons ;-)
[source,python]
----
from django.contrib.auth import backends, get_user_model
from ldap3 import Server, Connection, ALL
from ldap3.core.exceptions import LDAPPasswordIsMandatoryError
from config import settings
UserModel = get_user_model()
class LdapBackend(backends.ModelBackend):
"""Implémentation du backend LDAP pour la connexion des utilisateurs à l'Active Directory.
"""
def authenticate(self, request, username=None, password=None, **kwargs):
"""Authentifie l'utilisateur au travers du serveur LDAP.
"""
ldap_server = Server(settings.LDAP_SERVER, get_info=ALL)
ldap_connection = Connection(ldap_server, user=username, password=password)
try:
if not ldap_connection.bind():
raise ValueError("Login ou mot de passe incorrect")
except (LDAPPasswordIsMandatoryError, ValueError) as ldap_exception:
raise ldap_exception
user, _ = UserModel.objects.get_or_create(username=username)
----
On peut résumer le mécanisme d'authentification de la manière suivante:
* Si vous voulez modifier les informations liées à un utilisateur, orientez-vous vers la modification du modèle. Comme nous le verrons ci-dessous, il existe trois manières de prendre ces modifications en compte. Voir également `ici <https://docs.djangoproject.com/en/1.9/topics/auth/customizing/>`_.
@ -48,7 +140,7 @@ Notez bien qu'**il ne faut pas** spécifier le package ``.models`` dans cette in
Backend
=======
[blabla...]
*********

View File

@ -0,0 +1,28 @@
Templates tags
--------------
[source,python]
----
from django.template.defaultfilters import urlize
class Suggestion(BaseModel):
"""Représentation des suggestions.
"""
created_by = models.ForeignKey(user_model, on_delete=models.DO_NOTHING, verbose_name="Créé par")
manager = models.ForeignKey(
user_model,
on_delete=models.DO_NOTHING,
verbose_name="Gestionnaire",
null=True,
blank=True,
related_name="managed_by"
)
subject = models.TextField(verbose_name="Sujet")
def urlized_subject(self):
"""
Voir https://docs.djangoproject.com/fr/3.0/howto/custom-template-tags/
"""
return urlize(self.subject, autoescape=True)
----