{"title":"Gestion des mots de passe dans Django","version":"5.2","locale":"fr","docname":"topics/auth/passwords","url":"/fr/5.2/topics/auth/passwords/","canonical":"https://djangodocs.dev/fr/5.2/topics/auth/passwords/","summary":"La gestion des mots de passe est quelque chose qui ne devrait généralement pas être réinventé sans raison, et Django s’efforce de fournir un ensemble d’outils…","html":"<h1>Gestion des mots de passe dans Django<a class=\"heading-anchor\" href=\"#password-management-in-django\"><span class=\"visually-hidden\">Lien vers cette rubrique</span><span aria-hidden=\"true\">#</span></a></h1>\n<p>La gestion des mots de passe est quelque chose qui ne devrait généralement pas être réinventé sans raison, et Django s’efforce de fournir un ensemble d’outils sécurisés et souples pour gérer les mots de passe des utilisateurs. Ce document présente la façon dont Django stocke les mots de passe, la configuration possible du hachage avant stockage et certains utilitaires pour manipuler les empreintes de mots de passe.</p>\n<aside class=\"admonition admonition-seealso\">\n<p class=\"admonition-title\">Voir aussi</p>\n<p>Même si les utilisateurs utilisent des mots de passe forts, des attaquants peuvent arriver à écouter leurs connexions. Utilisez <a class=\"reference internal\" href=\"/fr/5.2/topics/security/#security-recommendation-ssl\"><span class=\"std std-ref\">HTTPS</span></a> afin d’éviter d’envoyer des mots de passe (ou d’autres données sensibles) sur des connexions HTTP simples car celles-ci sont vulnérables à l’interception de mots de passe.</p>\n</aside>\n<section id=\"how-django-stores-passwords\">\n<span id=\"auth-password-storage\"></span><h2>Stockage des mots de passe par Django<a class=\"heading-anchor\" href=\"#how-django-stores-passwords\"><span class=\"visually-hidden\">Lien vers cette rubrique</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>Django fournit un système de stockage de mots de passe souple et emploie PBKDF2 par défaut.</p>\n<p>L’attribut <a class=\"reference internal\" href=\"/fr/5.2/ref/contrib/auth/#django.contrib.auth.models.User.password\" title=\"django.contrib.auth.models.User.password\"><code class=\"xref py py-attr docutils literal notranslate\"><span class=\"pre\">password</span></code></a> d’un objet <a class=\"reference internal\" href=\"/fr/5.2/ref/contrib/auth/#django.contrib.auth.models.User\" title=\"django.contrib.auth.models.User\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">User</span></code></a> est une chaîne dans ce format :</p>\n<div class=\"code-block\" data-language=\"text\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Text</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Text code\"><code>&lt;algorithm&gt;$&lt;iterations&gt;$&lt;salt&gt;$&lt;hash&gt;\n</code></pre></div>\n<p>Il s’agit des composants utilisés pour stocker le mot de passe d’un utilisateur, séparés par le caractère dollar et formés de : l’algorithme de hachage, le nombre d’itérations de l’algorithme (facteur travail), le sel aléatoire et l’empreinte de mot de passe résultante. L’algorithme correspond à l’un des algorithmes de stockage de mot de passe ou de hachage à sens unique que Django peut utiliser ; voir ci-dessous. Les itérations indiquent le nombre de fois que l’algorithme traite l’empreinte numérique. Le sel est la graine aléatoire utilisée et l’empreinte est le résultat de la fonction à sens unique.</p>\n<p>Par défaut, Django utilise l’algorithme <a class=\"reference external\" href=\"https://en.wikipedia.org/wiki/PBKDF2\">PBKDF2</a> avec une fonction de hachage SHA256, un mécanisme d’étirement de mot de passe recommandé par le <a class=\"reference external\" href=\"https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-132.pdf\">NIST</a>. Cela devrait suffire pour la plupart des utilisateurs : c’est un algorithme bien sécurisé et exigeant d’énormes quantités de puissance de calcul pour être cassé.</p>\n<p>Cependant, en fonction de vos exigences, vous pouvez choisir un algorithme différent ou même utiliser un algorithme qui vous est propre pour répondre à votre situation spécifique en matière de sécurité. Encore une fois, la plupart des utilisateurs n’auront pas à le faire et si vous n’êtes pas sûr, c’est que vous n’en avez probablement pas besoin. Si vous en avez besoin, continuez cette lecture…</p>\n<p>Django choisit l’algorithme à utiliser en consultant le réglage <a class=\"reference internal\" href=\"/fr/5.2/ref/settings/#std-setting-PASSWORD_HASHERS\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">PASSWORD_HASHERS</span></code></a>. Il s’agit d’une liste de classes d’algorithme de hachage que la présente installation de Django prend en charge.</p>\n<p>Pour le stockage des mots de passe, Django utilise le premier algorithme de <a class=\"reference internal\" href=\"/fr/5.2/ref/settings/#std-setting-PASSWORD_HASHERS\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">PASSWORD_HASHERS</span></code></a>. Pour stocker les nouveaux mots de passe avec un algorithme différent, placez votre algorithme préféré en première position dans <a class=\"reference internal\" href=\"/fr/5.2/ref/settings/#std-setting-PASSWORD_HASHERS\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">PASSWORD_HASHERS</span></code></a>.</p>\n<p>Pour la vérification des mots de passe, Django recherche dans la liste l’algorithme de hachage qui correspond au nom d’algorithme dans le mot de passe stocké. Dans le cas où un nom d’algorithme stocké dans un mot de passe n’est pas trouvé dans <a class=\"reference internal\" href=\"/fr/5.2/ref/settings/#std-setting-PASSWORD_HASHERS\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">PASSWORD_HASHERS</span></code></a>, sa vérification génère une exception <code class=\"docutils literal notranslate\"><span class=\"pre\">ValueError</span></code>.</p>\n<p>La valeur par défaut de <a class=\"reference internal\" href=\"/fr/5.2/ref/settings/#std-setting-PASSWORD_HASHERS\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">PASSWORD_HASHERS</span></code></a> est :</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"n\">PASSWORD_HASHERS</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.PBKDF2PasswordHasher&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.Argon2PasswordHasher&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.BCryptSHA256PasswordHasher&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.ScryptPasswordHasher&quot;</span><span class=\"p\">,</span>\n<span class=\"p\">]</span>\n</code></pre></div>\n<p>Cela signifie que Django utilisera <a class=\"reference external\" href=\"https://en.wikipedia.org/wiki/PBKDF2\">PBKDF2</a> pour stocker tous les mots de passe, mais qu’il acceptera de vérifier des mots de passe stockés avec les algorithmes PBKDF2SHA1, <a class=\"reference external\" href=\"https://en.wikipedia.org/wiki/Argon2\">argon2</a> et <a class=\"reference external\" href=\"https://en.wikipedia.org/wiki/Bcrypt\">bcrypt</a>.</p>\n<p>Les sections qui suivent présentent quelques manières fréquentes que les utilisateurs avancés peuvent utiliser pour modifier ce réglage.</p>\n<section id=\"using-argon2-with-django\">\n<span id=\"argon2-usage\"></span><h3>Utilisation de Argon2 avec Django<a class=\"heading-anchor\" href=\"#using-argon2-with-django\"><span class=\"visually-hidden\">Lien vers cette rubrique</span><span aria-hidden=\"true\">#</span></a></h3>\n<p><a class=\"reference external\" href=\"https://en.wikipedia.org/wiki/Argon2\">Argon2</a> est le gagnant du concours 2015 <a class=\"reference external\" href=\"https://www.password-hashing.net/\">Password Hashing Competition</a>, une compétition ouverte organisée par la communauté pour sélectionner un algorithme de hachage de nouvelle génération. Il est conçu pour ne pas être plus facile à calculer sur du matériel dédié qu’il ne l’est sur un processeur ordinaire. La variante par défaut du hacheur de mot de passe Argon2 et Argon2id.</p>\n<p><a class=\"reference external\" href=\"https://en.wikipedia.org/wiki/Argon2\">Argon2</a> n’est pas l’algorithme utilisé par défaut dans Django car il nécessite une bibliothèque tierce. Les experts de Password Hashing Competition recommandent cependant l’utilisation immédiate de Argon2 plutôt que les autres algorithmes pris en charge par Django.</p>\n<p>Pour utiliser Argon2id comme algorithme de stockage par défaut, faites ceci :</p>\n<ol class=\"arabic\">\n<li><p>Installez le paquet <a class=\"extlink-pypi reference external\" href=\"https://pypi.org/project/argon2-cffi/\">argon2-cffi</a>. Cela peut se faire en lançant <code class=\"docutils literal notranslate\"><span class=\"pre\">python</span> <span class=\"pre\">-m</span> <span class=\"pre\">pip</span> <span class=\"pre\">install</span> <span class=\"pre\">django[argon2]</span></code>, ce qui est équivalent à <code class=\"docutils literal notranslate\"><span class=\"pre\">python</span> <span class=\"pre\">-m</span> <span class=\"pre\">pip</span> <span class=\"pre\">install</span> <span class=\"pre\">argon2-cffi</span></code> (en installant aussi toute version de paquet exigée par le fichier <code class=\"docutils literal notranslate\"><span class=\"pre\">pyproject.toml</span></code> de Django).</p></li>\n<li><p>Modifiez <a class=\"reference internal\" href=\"/fr/5.2/ref/settings/#std-setting-PASSWORD_HASHERS\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">PASSWORD_HASHERS</span></code></a> pour que <code class=\"docutils literal notranslate\"><span class=\"pre\">Argon2PasswordHasher</span></code> apparaisse en premier. Voici ce qui devrait apparaître dans votre fichier de réglages :</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"n\">PASSWORD_HASHERS</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.Argon2PasswordHasher&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.PBKDF2PasswordHasher&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.BCryptSHA256PasswordHasher&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.ScryptPasswordHasher&quot;</span><span class=\"p\">,</span>\n<span class=\"p\">]</span>\n</code></pre></div>\n<p>Conservez ou ajoutez d’autres éléments dans cette liste si vous avez besoin que Django puisse <a class=\"reference internal\" href=\"#password-upgrades\"><span class=\"std std-ref\">mettre à jour des mots de passe</span></a>.</p>\n</li>\n</ol>\n</section>\n<section id=\"using-bcrypt-with-django\">\n<span id=\"bcrypt-usage\"></span><h3>Utilisation de <code class=\"docutils literal notranslate\"><span class=\"pre\">bcrypt</span></code> avec Django<a class=\"heading-anchor\" href=\"#using-bcrypt-with-django\"><span class=\"visually-hidden\">Lien vers cette rubrique</span><span aria-hidden=\"true\">#</span></a></h3>\n<p><a class=\"reference external\" href=\"https://en.wikipedia.org/wiki/Bcrypt\">Bcrypt</a> est un algorithme de stockage de mot de passe répandu qui est spécifiquement conçu comme stockage de mots de passe à long terme. Ce n’est pas l’algorithme par défaut de Django car il dépend de l’installation de bibliothèques tierces. Mais comme il y a beaucoup d’utilisateurs potentiels, Django prend en charge bcrypt avec un minimum d’effort.</p>\n<p>Pour utiliser Bcrypt comme algorithme de stockage par défaut, faites ceci :</p>\n<ol class=\"arabic\">\n<li><p>Installez le paquet <a class=\"extlink-pypi reference external\" href=\"https://pypi.org/project/bcrypt/\">bcrypt</a>. Cela peut se faire en lançant <code class=\"docutils literal notranslate\"><span class=\"pre\">python</span> <span class=\"pre\">-m</span> <span class=\"pre\">pip</span> <span class=\"pre\">install</span> <span class=\"pre\">django[bcrypt]</span></code>, ce qui est équivalent à <code class=\"docutils literal notranslate\"><span class=\"pre\">python</span> <span class=\"pre\">-m</span> <span class=\"pre\">pip</span> <span class=\"pre\">install</span> <span class=\"pre\">bcrypt</span></code> (en installant aussi toute version de paquet exigée par le fichier <code class=\"docutils literal notranslate\"><span class=\"pre\">pyproject.toml</span></code> de Django).</p></li>\n<li><p>Modifiez <a class=\"reference internal\" href=\"/fr/5.2/ref/settings/#std-setting-PASSWORD_HASHERS\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">PASSWORD_HASHERS</span></code></a> pour que <code class=\"docutils literal notranslate\"><span class=\"pre\">BCryptSHA256PasswordHasher</span></code> apparaisse en premier. Voici ce qui devrait apparaître dans votre fichier de réglages :</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"n\">PASSWORD_HASHERS</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.BCryptSHA256PasswordHasher&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.PBKDF2PasswordHasher&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.Argon2PasswordHasher&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.ScryptPasswordHasher&quot;</span><span class=\"p\">,</span>\n<span class=\"p\">]</span>\n</code></pre></div>\n<p>Conservez ou ajoutez d’autres éléments dans cette liste si vous avez besoin que Django puisse <a class=\"reference internal\" href=\"#password-upgrades\"><span class=\"std std-ref\">mettre à jour des mots de passe</span></a>.</p>\n</li>\n</ol>\n<p>Et voilà, votre installation Django utilise dorénavant Bcrypt comme algorithme de stockage par défaut.</p>\n</section>\n<section id=\"using-scrypt-with-django\">\n<span id=\"scrypt-usage\"></span><h3>Utilisation de <code class=\"docutils literal notranslate\"><span class=\"pre\">scrypt</span></code> avec Django<a class=\"heading-anchor\" href=\"#using-scrypt-with-django\"><span class=\"visually-hidden\">Lien vers cette rubrique</span><span aria-hidden=\"true\">#</span></a></h3>\n<p><a class=\"reference external\" href=\"https://en.wikipedia.org/wiki/Scrypt\">scrypt</a> est semblable à PBKDF2 et à bcrypt dans le sens où il utilise un nombre d’itérations pour ralentir les attaques par force brute. Cependant, comme PBKDF2 et bcrypt ne nécessitent pas beaucoup de mémoire, des attaquants avec suffisamment de ressources peuvent lancer des attaques en parallèle et à large échelle afin d’accélérer le processus d’attaque. <a class=\"reference external\" href=\"https://en.wikipedia.org/wiki/Scrypt\">scrypt</a> est spécifiquement conçu pour utiliser plus de mémoire en comparaison d’autres fonctions de dérivation de clé basées sur des mots de passe, afin de limiter la capacité de parallélisme d’un éventuel attaquant. Voir <span class=\"target\" id=\"index-2\"></span><a class=\"rfc reference external\" href=\"https://datatracker.ietf.org/doc/html/rfc7914.html\"><strong>RFC 7914</strong></a> pour plus de détails.</p>\n<p>Pour utiliser <a class=\"reference external\" href=\"https://en.wikipedia.org/wiki/Scrypt\">scrypt</a> comme algorithme de stockage par défaut, faites ceci :</p>\n<ol class=\"arabic\">\n<li><p>Modifiez <a class=\"reference internal\" href=\"/fr/5.2/ref/settings/#std-setting-PASSWORD_HASHERS\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">PASSWORD_HASHERS</span></code></a> pour que <code class=\"docutils literal notranslate\"><span class=\"pre\">ScryptPasswordHasher</span></code> apparaisse en premier. Voici ce qui devrait apparaître dans votre fichier de réglages :</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"n\">PASSWORD_HASHERS</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.ScryptPasswordHasher&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.PBKDF2PasswordHasher&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.Argon2PasswordHasher&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.BCryptSHA256PasswordHasher&quot;</span><span class=\"p\">,</span>\n<span class=\"p\">]</span>\n</code></pre></div>\n<p>Conservez ou ajoutez d’autres éléments dans cette liste si vous avez besoin que Django puisse <a class=\"reference internal\" href=\"#password-upgrades\"><span class=\"std std-ref\">mettre à jour des mots de passe</span></a>.</p>\n</li>\n</ol>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">Note</p>\n<p><code class=\"docutils literal notranslate\"><span class=\"pre\">scrypt</span></code> nécessite OpenSSL 1.1+.</p>\n</aside>\n</section>\n<section id=\"increasing-the-salt-entropy\">\n<h3>Augmentation de l’entropie du sel<a class=\"heading-anchor\" href=\"#increasing-the-salt-entropy\"><span class=\"visually-hidden\">Lien vers cette rubrique</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>La plupart de hacheurs de mots de passe incluent un sel dans l’empreinte du mot de passe afin de protéger contre les attaques par table arc-en-ciel. Le sel est lui-même une valeur aléatoire qui augmente la taille et donc le coût de la table arc-en-ciel ; elle possède actuellement 128 bits par la valeur  <code class=\"docutils literal notranslate\"><span class=\"pre\">salt_entropy</span></code> dans <code class=\"docutils literal notranslate\"><span class=\"pre\">BasePasswordHasher</span></code>. Comme les coûts de calcul et de stockage diminuent avec le temps, cette valeur doit augmenter. Si vous implémentez votre propre hacheur de mots de passe, vous êtes libre de surcharger cette valeur pour atteindre le niveau d’entropie souhaité pour votre hacheur de mots de passe. <code class=\"docutils literal notranslate\"><span class=\"pre\">salt_entropy</span></code> est une mesure en bits.</p>\n<aside class=\"admonition-implementation-detail admonition\">\n<p class=\"admonition-title\">Détails d’implémentation</p>\n<p>En raison de la méthode avec laquelle les valeurs de sel sont stockées, la valeur <code class=\"docutils literal notranslate\"><span class=\"pre\">salt_entropy</span></code> est effectivement une valeur minimale. Par exemple, une valeur de 128 produit un sel qui contient en réalité 131 bits d’entropie.</p>\n</aside>\n</section>\n<section id=\"increasing-the-work-factor\">\n<span id=\"increasing-password-algorithm-work-factor\"></span><h3>Augmentation du facteur travail<a class=\"heading-anchor\" href=\"#increasing-the-work-factor\"><span class=\"visually-hidden\">Lien vers cette rubrique</span><span aria-hidden=\"true\">#</span></a></h3>\n<section id=\"pbkdf2-and-bcrypt\">\n<h4>PBKDF2 et bcrypt<a class=\"heading-anchor\" href=\"#pbkdf2-and-bcrypt\"><span class=\"visually-hidden\">Lien vers cette rubrique</span><span aria-hidden=\"true\">#</span></a></h4>\n<p>Les algorithmes PBKDF2 et bcrypt utilisent un certain nombre d’itérations ou de passes de hachage. Cela ralentit volontairement les attaques, rendant plus difficiles les attaques contre les empreintes de mots de passe. Cependant, au fur et à mesure de l’augmentation des puissances de calcul, le nombre d’itérations nécessaires augmente également. Nous avons opté pour une valeur par défaut raisonnable (et nous l’augmenterons avec chaque nouvelle publication de Django), mais vous pouvez l’augmenter ou la réduire en fonction de vos besoins de sécurité et de vos capacités en puissance de calcul. Pour cela, vous pouvez créer une sous-classe de l’algorithme approprié et surcharger le paramètre <code class=\"docutils literal notranslate\"><span class=\"pre\">iterations</span></code> (utilisez le paramètre <code class=\"docutils literal notranslate\"><span class=\"pre\">rounds</span></code> lors d’un héritage du hacheur bcrypt). Par exemple, pour augmenter le nombre d’itérations utilisé par l’algorithme par défaut PBKDF2 :</p>\n<ol class=\"arabic\">\n<li><p>Créez une sous-classe de <code class=\"docutils literal notranslate\"><span class=\"pre\">django.contrib.auth.hashers.PBKDF2PasswordHasher</span></code>:</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.contrib.auth.hashers</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">PBKDF2PasswordHasher</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">MyPBKDF2PasswordHasher</span><span class=\"p\">(</span><span class=\"n\">PBKDF2PasswordHasher</span><span class=\"p\">):</span>\n<span class=\"w\">    </span><span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    A subclass of PBKDF2PasswordHasher that uses 100 times more iterations.</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n\n    <span class=\"n\">iterations</span> <span class=\"o\">=</span> <span class=\"n\">PBKDF2PasswordHasher</span><span class=\"o\">.</span><span class=\"n\">iterations</span> <span class=\"o\">*</span> <span class=\"mi\">100</span>\n</code></pre></div>\n<p>Enregistrez-la quelque part dans votre projet. Par exemple, vous pourriez la placer dans un fichier nommé <code class=\"docutils literal notranslate\"><span class=\"pre\">myproject/hashers.py</span></code>.</p>\n</li>\n<li><p>Ajoutez votre nouvelle classe de hachage en premier dans <a class=\"reference internal\" href=\"/fr/5.2/ref/settings/#std-setting-PASSWORD_HASHERS\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">PASSWORD_HASHERS</span></code></a>:</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"n\">PASSWORD_HASHERS</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n    <span class=\"s2\">&quot;myproject.hashers.MyPBKDF2PasswordHasher&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.PBKDF2PasswordHasher&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.Argon2PasswordHasher&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.BCryptSHA256PasswordHasher&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.ScryptPasswordHasher&quot;</span><span class=\"p\">,</span>\n<span class=\"p\">]</span>\n</code></pre></div>\n</li>\n</ol>\n<p>Et voilà, votre installation Django utilise dorénavant plus d’itérations lorsqu’elle stockera les mots de passe avec PBKDF2.</p>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">Note</p>\n<p>Le paramètre <code class=\"docutils literal notranslate\"><span class=\"pre\">rounds</span></code> de bcrypt est un facteur de travail logarithmique, par ex. 12 rounds signifie <code class=\"docutils literal notranslate\"><span class=\"pre\">2</span> <span class=\"pre\">**</span> <span class=\"pre\">12</span></code> itérations.</p>\n</aside>\n</section>\n<section id=\"argon2\">\n<h4>Argon2<a class=\"heading-anchor\" href=\"#argon2\"><span class=\"visually-hidden\">Lien vers cette rubrique</span><span aria-hidden=\"true\">#</span></a></h4>\n<p>Argon2 possède les attributs suivants qui peuvent être personnalisés :</p>\n<ol class=\"arabic simple\">\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">time_cost</span></code> contrôle le nombre d’itérations pour l’empreinte.</p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">memory_cost</span></code> contrôle la taille mémoire utilisée lors du calcul de l’empreinte.</p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">parallelism</span></code> contrôle le nombre de processeurs pouvant être mis à contribution pour le calcul de l’empreinte.</p></li>\n</ol>\n<p>Les valeurs par défaut de ces attributs sont probablement raisonnables. Si vous déterminez que le hachage des mots de passe est trop rapide ou trop lent, vous pouvez les ajuster comme suit :</p>\n<ol class=\"arabic simple\">\n<li><p>Définissez <code class=\"docutils literal notranslate\"><span class=\"pre\">parallelism</span></code> au nombre de fils d’exécution à exploiter pour le calcul de l’empreinte.</p></li>\n<li><p>Définissez <code class=\"docutils literal notranslate\"><span class=\"pre\">memory_cost</span></code> au nombre de Kio de mémoire à exploiter.</p></li>\n<li><p>Ajustez <code class=\"docutils literal notranslate\"><span class=\"pre\">time_cost</span></code> et mesurez le temps passé à hacher un mot de passe. Choisissez une valeur <code class=\"docutils literal notranslate\"><span class=\"pre\">time_cost</span></code> qui consomme un temps acceptable pour vous. Si <code class=\"docutils literal notranslate\"><span class=\"pre\">time_cost</span></code> défini à 1 est encore trop lent, baissez la valeur <code class=\"docutils literal notranslate\"><span class=\"pre\">memory_cost</span></code>.</p></li>\n</ol>\n<aside class=\"admonition-memory-cost-interpretation admonition\">\n<p class=\"admonition-title\">Interprétation de <code class=\"docutils literal notranslate\"><span class=\"pre\">memory_cost</span></code></p>\n<p>L’utilitaire en ligne de commande argon2 et certaines autres bibliothèques interprètent le paramètre <code class=\"docutils literal notranslate\"><span class=\"pre\">memory_cost</span></code> différemment de la valeur que Django utilise. La conversion est donnée par <code class=\"docutils literal notranslate\"><span class=\"pre\">memory_cost</span> <span class=\"pre\">==</span> <span class=\"pre\">2</span> <span class=\"pre\">**</span> <span class=\"pre\">memory_cost_en_ligne_de_commande</span></code>.</p>\n</aside>\n</section>\n<section id=\"scrypt\">\n<h4><code class=\"docutils literal notranslate\"><span class=\"pre\">scrypt</span></code><a class=\"heading-anchor\" href=\"#scrypt\"><span class=\"visually-hidden\">Lien vers cette rubrique</span><span aria-hidden=\"true\">#</span></a></h4>\n<p><a class=\"reference external\" href=\"https://en.wikipedia.org/wiki/Scrypt\">scrypt</a> possède les attributs suivants qui peuvent être personnalisés :</p>\n<ol class=\"arabic simple\">\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">work_factor</span></code> contrôle le nombre d’itérations pour l’empreinte.</p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">block_size</span></code></p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">parallelism</span></code> contrôle le nombre de fils d’exécution lancés en parallèle.</p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">maxmem</span></code> limite la taille mémoire maximale pouvant être utilisée lors du calcul de l’empreinte. La velur par défaut est <code class=\"docutils literal notranslate\"><span class=\"pre\">0</span></code>, ce qui indique que c’est la valeur par défaut de la bibliothèque OpenSSL qui sera utilisée.</p></li>\n</ol>\n<p>Nous avons choisi des valeurs par défaut raisonnable, mais vous pouvez les ajuster vers le haut ou vers le bas en fonction de vox exigences de sécurité et de votre puissance de calcul disponible.</p>\n<aside class=\"admonition-estimating-memory-usage admonition\">\n<p class=\"admonition-title\">Estimation de l’utilisation de la mémoire</p>\n<p>L’exigence minimale de mémoire pour <a class=\"reference external\" href=\"https://en.wikipedia.org/wiki/Scrypt\">scrypt</a> est</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"n\">work_factor</span> <span class=\"o\">*</span> <span class=\"mi\">2</span> <span class=\"o\">*</span> <span class=\"n\">block_size</span> <span class=\"o\">*</span> <span class=\"mi\">64</span>\n</code></pre></div>\n<p>ce qui implique que vous pourriez devoir ajuster <code class=\"docutils literal notranslate\"><span class=\"pre\">maxmem</span></code> lorsque vous modifiez les valeurs de <code class=\"docutils literal notranslate\"><span class=\"pre\">work_factor</span></code> ou <code class=\"docutils literal notranslate\"><span class=\"pre\">block_size</span></code>.</p>\n</aside>\n</section>\n</section>\n<section id=\"password-upgrading\">\n<span id=\"password-upgrades\"></span><h3>Mise à niveau des mots de passe<a class=\"heading-anchor\" href=\"#password-upgrading\"><span class=\"visually-hidden\">Lien vers cette rubrique</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>Lorsque les utilisateurs se connectent, si leur mot de passe est stocké avec un autre algorithme que celui qui est défini comme le principal, Django met automatiquement à jour l’algorithme pour utiliser ce dernier. Cela signifie que d’anciennes installations de Django deviennent automatiquement plus sécurisées au fur et à mesure que les utilisateurs se connectent, et cela signifie également que vous pouvez passer à de nouveaux (et meilleurs) algorithmes de stockage au moment où ils deviennent disponibles.</p>\n<p>Cependant, Django peut uniquement mettre à jour les mots de passe utilisant des algorithmes mentionnés dans <a class=\"reference internal\" href=\"/fr/5.2/ref/settings/#std-setting-PASSWORD_HASHERS\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">PASSWORD_HASHERS</span></code></a>, il est donc important de ne pas <em>enlever</em> les anciens algorithmes de cette liste quand vous passez à de nouveaux systèmes. Si vous le faites, les utilisateurs utilisant des algorithmes non mentionnés ne pourront pas mettre à jour leur mot de passe. Les mots de passe hachés sont mis à jour lorsque le nombre d’itérations PBKDF2, de tours bcrypt ou d’attributs argon2 est augmenté (ou réduit).</p>\n<p>Soyez conscients que si tous les mots de passe de votre base de données se sont pas codés avec l’algorithme de hachage par défaut, il est possible que vous soyez vulnérable à une attaque de type énumération de compte basée sur le temps en raison d’une différence entre la durée d’une requête de connexion pour un utilisateur avec mot de passe codé dans un algorithme différent et la durée d’une requête de connexion d’un utilisateur non existant (qui exécute l’algorithme par défaut). Il est possible de relativiser ce problème en <a class=\"reference internal\" href=\"#wrapping-password-hashers\"><span class=\"std std-ref\">mettant à jour les anciennes empreintes de mot de passe</span></a>.</p>\n</section>\n<section id=\"password-upgrading-without-requiring-a-login\">\n<span id=\"wrapping-password-hashers\"></span><h3>Mise à jour des mots de passe sans exiger de connexion<a class=\"heading-anchor\" href=\"#password-upgrading-without-requiring-a-login\"><span class=\"visually-hidden\">Lien vers cette rubrique</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>Si une base de données existante comporte des empreintes de mots de passe anciennes et vulnérables de type MD5, il peut être souhaitable de mettre à jour ces empreintes sans devoir attendre que les utilisateurs concernés se connectent (ce qui pourrait ne jamais arriver si ces utilisateurs ne reviennent plus sur le site). Dans ce cas, vous pouvez utiliser un hacheur de mots de passe « enveloppé ».</p>\n<p>Pour cet exemple, nous allons migrer une série d’empreintes MD5 afin qu’elles utilisent PBKDF2(MD5(mot_de_passe)) et ajouter le hacheur de mot de passe correspondant qui se chargera de vérifier le mot de passe de l’utilisateur lors d’une connexion. Nous partons du principe que c’est le modèle d’utilisateur par défaut qui est utilisé et que le projet possède une application <code class=\"docutils literal notranslate\"><span class=\"pre\">accounts</span></code>. Vous pouvez modifier cet exemple pour qu’il fonctionne avec tout autre algorithme ou avec un modèle d’utilisateur personnalisé.</p>\n<p>Nous allons d’abord ajouter le hacheur personnalisé :</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\"><code class=\"docutils literal notranslate\"><span class=\"pre\">accounts/hashers.py</span></code></figcaption>\n<div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.contrib.auth.hashers</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"p\">(</span>\n    <span class=\"n\">PBKDF2PasswordHasher</span><span class=\"p\">,</span>\n    <span class=\"n\">MD5PasswordHasher</span><span class=\"p\">,</span>\n<span class=\"p\">)</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">PBKDF2WrappedMD5PasswordHasher</span><span class=\"p\">(</span><span class=\"n\">PBKDF2PasswordHasher</span><span class=\"p\">):</span>\n    <span class=\"n\">algorithm</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;pbkdf2_wrapped_md5&quot;</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">encode_md5_hash</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">md5_hash</span><span class=\"p\">,</span> <span class=\"n\">salt</span><span class=\"p\">,</span> <span class=\"n\">iterations</span><span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"nb\">super</span><span class=\"p\">()</span><span class=\"o\">.</span><span class=\"n\">encode</span><span class=\"p\">(</span><span class=\"n\">md5_hash</span><span class=\"p\">,</span> <span class=\"n\">salt</span><span class=\"p\">,</span> <span class=\"n\">iterations</span><span class=\"p\">)</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">encode</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">password</span><span class=\"p\">,</span> <span class=\"n\">salt</span><span class=\"p\">,</span> <span class=\"n\">iterations</span><span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">):</span>\n        <span class=\"n\">_</span><span class=\"p\">,</span> <span class=\"n\">_</span><span class=\"p\">,</span> <span class=\"n\">md5_hash</span> <span class=\"o\">=</span> <span class=\"n\">MD5PasswordHasher</span><span class=\"p\">()</span><span class=\"o\">.</span><span class=\"n\">encode</span><span class=\"p\">(</span><span class=\"n\">password</span><span class=\"p\">,</span> <span class=\"n\">salt</span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"n\">split</span><span class=\"p\">(</span><span class=\"s2\">&quot;$&quot;</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">encode_md5_hash</span><span class=\"p\">(</span><span class=\"n\">md5_hash</span><span class=\"p\">,</span> <span class=\"n\">salt</span><span class=\"p\">,</span> <span class=\"n\">iterations</span><span class=\"p\">)</span>\n</code></pre></figure>\n<p>La migration de données pourrait ressembler à ceci :</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\"><code class=\"docutils literal notranslate\"><span class=\"pre\">accounts/migrations/0002_migrate_md5_passwords.py</span></code></figcaption>\n<div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.db</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">migrations</span>\n\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">..hashers</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">PBKDF2WrappedMD5PasswordHasher</span>\n\n\n<span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">forwards_func</span><span class=\"p\">(</span><span class=\"n\">apps</span><span class=\"p\">,</span> <span class=\"n\">schema_editor</span><span class=\"p\">):</span>\n    <span class=\"n\">User</span> <span class=\"o\">=</span> <span class=\"n\">apps</span><span class=\"o\">.</span><span class=\"n\">get_model</span><span class=\"p\">(</span><span class=\"s2\">&quot;auth&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;User&quot;</span><span class=\"p\">)</span>\n    <span class=\"n\">users</span> <span class=\"o\">=</span> <span class=\"n\">User</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">filter</span><span class=\"p\">(</span><span class=\"n\">password__startswith</span><span class=\"o\">=</span><span class=\"s2\">&quot;md5$&quot;</span><span class=\"p\">)</span>\n    <span class=\"n\">hasher</span> <span class=\"o\">=</span> <span class=\"n\">PBKDF2WrappedMD5PasswordHasher</span><span class=\"p\">()</span>\n    <span class=\"k\">for</span> <span class=\"n\">user</span> <span class=\"ow\">in</span> <span class=\"n\">users</span><span class=\"p\">:</span>\n        <span class=\"n\">algorithm</span><span class=\"p\">,</span> <span class=\"n\">salt</span><span class=\"p\">,</span> <span class=\"n\">md5_hash</span> <span class=\"o\">=</span> <span class=\"n\">user</span><span class=\"o\">.</span><span class=\"n\">password</span><span class=\"o\">.</span><span class=\"n\">split</span><span class=\"p\">(</span><span class=\"s2\">&quot;$&quot;</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">)</span>\n        <span class=\"n\">user</span><span class=\"o\">.</span><span class=\"n\">password</span> <span class=\"o\">=</span> <span class=\"n\">hasher</span><span class=\"o\">.</span><span class=\"n\">encode_md5_hash</span><span class=\"p\">(</span><span class=\"n\">md5_hash</span><span class=\"p\">,</span> <span class=\"n\">salt</span><span class=\"p\">)</span>\n        <span class=\"n\">user</span><span class=\"o\">.</span><span class=\"n\">save</span><span class=\"p\">(</span><span class=\"n\">update_fields</span><span class=\"o\">=</span><span class=\"p\">[</span><span class=\"s2\">&quot;password&quot;</span><span class=\"p\">])</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">Migration</span><span class=\"p\">(</span><span class=\"n\">migrations</span><span class=\"o\">.</span><span class=\"n\">Migration</span><span class=\"p\">):</span>\n    <span class=\"n\">dependencies</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n        <span class=\"p\">(</span><span class=\"s2\">&quot;accounts&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;0001_initial&quot;</span><span class=\"p\">),</span>\n        <span class=\"c1\"># replace this with the latest migration in contrib.auth</span>\n        <span class=\"p\">(</span><span class=\"s2\">&quot;auth&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;####_migration_name&quot;</span><span class=\"p\">),</span>\n    <span class=\"p\">]</span>\n\n    <span class=\"n\">operations</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n        <span class=\"n\">migrations</span><span class=\"o\">.</span><span class=\"n\">RunPython</span><span class=\"p\">(</span><span class=\"n\">forwards_func</span><span class=\"p\">),</span>\n    <span class=\"p\">]</span>\n</code></pre></figure>\n<p>Il faut savoir que cette migration va prendre plusieurs minutes pour quelques milliers d’utilisateurs, en fonction de la performance de votre matériel.</p>\n<p>Pour terminer, nous allons ajouter un réglage <a class=\"reference internal\" href=\"/fr/5.2/ref/settings/#std-setting-PASSWORD_HASHERS\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">PASSWORD_HASHERS</span></code></a>:</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\"><code class=\"docutils literal notranslate\"><span class=\"pre\">mysite/settings.py</span></code></figcaption>\n<div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"n\">PASSWORD_HASHERS</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.PBKDF2PasswordHasher&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;accounts.hashers.PBKDF2WrappedMD5PasswordHasher&quot;</span><span class=\"p\">,</span>\n<span class=\"p\">]</span>\n</code></pre></figure>\n<p>Incluez tout autre hacheur utilisé par votre site dans cette liste.</p>\n</section>\n<section id=\"included-hashers\">\n<span id=\"auth-included-hashers\"></span><h3>Hacheurs de mots de passe intégrés<a class=\"heading-anchor\" href=\"#included-hashers\"><span class=\"visually-hidden\">Lien vers cette rubrique</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>La liste complète de hacheurs de mots de passe inclus dans Django est :</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"p\">[</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.PBKDF2PasswordHasher&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.Argon2PasswordHasher&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.BCryptSHA256PasswordHasher&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.BCryptPasswordHasher&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.ScryptPasswordHasher&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;django.contrib.auth.hashers.MD5PasswordHasher&quot;</span><span class=\"p\">,</span>\n<span class=\"p\">]</span>\n</code></pre></div>\n<p>Les noms d’algorithmes correspondants sont :</p>\n<ul class=\"simple\">\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">pbkdf2_sha256</span></code></p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">pbkdf2_sha1</span></code></p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">argon2</span></code></p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">bcrypt_sha256</span></code></p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">bcrypt</span></code></p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">scrypt</span></code></p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">md5</span></code></p></li>\n</ul>\n</section>\n<section id=\"writing-your-own-hasher\">\n<span id=\"write-your-own-password-hasher\"></span><h3>Écriture de son propre algorithme de hachage<a class=\"heading-anchor\" href=\"#writing-your-own-hasher\"><span class=\"visually-hidden\">Lien vers cette rubrique</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>Si vous écrivez votre propre algorithme de hachage de mot de passe doté d’un facteur de travail tel qu’un nombre d’itérations, vous devriez implémenter une méthode <code class=\"docutils literal notranslate\"><span class=\"pre\">harden_runtime(self,</span> <span class=\"pre\">password,</span> <span class=\"pre\">encoded)</span></code> pour compenser la différence de temps d’exécution entre le facteur de travail fourni dans le mot de passe <code class=\"docutils literal notranslate\"><span class=\"pre\">encoded</span></code> et le facteur de travail par défaut de l’algorithme. Ceci empêche les attaques de type énumération de compte basée sur le temps qui utilise la différence entre les requêtes de connexion d’un utilisateur dont le mot de passe est codé avec un ancien nombre d’itérations et un utilisateur inexistant (qui fait appel au nombre d’itérations par défaut de l’algorithme).</p>\n<p>En prenant PBKDF2 comme exemple, si <code class=\"docutils literal notranslate\"><span class=\"pre\">encoded</span></code> contient 20’000 itérations et que le nombre d’itérations par défaut de l’algorithme est de 30’000, la méthode devrait faire passer <code class=\"docutils literal notranslate\"><span class=\"pre\">password</span></code> à travers 10’000 itérations supplémentaires de PBKDF2.</p>\n<p>Si votre algorithme de hachage ne possède pas de facteur de travail, implémentez la méthode comme fictive (<code class=\"docutils literal notranslate\"><span class=\"pre\">pass</span></code>).</p>\n</section>\n</section>\n<section id=\"module-django.contrib.auth.hashers\">\n<span id=\"manually-managing-a-user-s-password\"></span><h2>Gestion manuelle des mots de passe<a class=\"heading-anchor\" href=\"#module-django.contrib.auth.hashers\"><span class=\"visually-hidden\">Lien vers cette rubrique</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>Le module <a class=\"reference internal\" href=\"#module-django.contrib.auth.hashers\" title=\"django.contrib.auth.hashers\"><code class=\"xref py py-mod docutils literal notranslate\"><span class=\"pre\">django.contrib.auth.hashers</span></code></a> fournit un ensemble de fonctions pour créer et valider les empreintes de mots de passe. Vous pouvez les utiliser indépendamment du modèle <code class=\"docutils literal notranslate\"><span class=\"pre\">User</span></code>.</p>\n<dl class=\"py function\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.hashers.check_password\">\n<span class=\"sig-name descname\"><span class=\"pre\">check_password</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">password</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">encoded</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">setter</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">None</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">preferred</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">'default'</span></span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.hashers.check_password\"><span class=\"visually-hidden\">Lien vers cette définition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd></dd></dl>\n\n<dl class=\"py function\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.hashers.acheck_password\">\n<span class=\"sig-name descname\"><span class=\"pre\">acheck_password</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">password</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">encoded</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">asetter</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">None</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">preferred</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">'default'</span></span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.hashers.acheck_password\"><span class=\"visually-hidden\">Lien vers cette définition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p><em>Version asynchrone</em>: <code class=\"docutils literal notranslate\"><span class=\"pre\">acheck_password()</span></code></p>\n<p>Si vous souhaitez  authentifier manuellement un utilisateur en comparant un mot de passe en clair à l’empreinte du mot de passe dans la base de données, utilisez la fonction <a class=\"reference internal\" href=\"#django.contrib.auth.hashers.check_password\" title=\"django.contrib.auth.hashers.check_password\"><code class=\"xref py py-func docutils literal notranslate\"><span class=\"pre\">check_password()</span></code></a>. Elle prend deux arguments obligatoires : le mot de passe en clair à vérifier et la valeur complète du champ <code class=\"docutils literal notranslate\"><span class=\"pre\">password</span></code> d’un utilisateur dans la base de données avec laquelle la vérification sera faite. Si le mot de passe est correcte, la fonction renvoie <code class=\"docutils literal notranslate\"><span class=\"pre\">True</span></code>, sinon <code class=\"docutils literal notranslate\"><span class=\"pre\">False</span></code>. Il est possible de transmettre en option un objet exécutable <code class=\"docutils literal notranslate\"><span class=\"pre\">setter</span></code> qui prend un mot de passe en paramètre et qui sera appelé au moment de le régénérer. Vous pouvez aussi transmettre <code class=\"docutils literal notranslate\"><span class=\"pre\">preferred</span></code> pour modifier l’algorithme de hachage si vous ne souhaitez pas utiliser l’algorithme par défaut (première ligne du réglage <code class=\"docutils literal notranslate\"><span class=\"pre\">PASSWORD_HASHERS</span></code>). Voir <a class=\"reference internal\" href=\"#auth-included-hashers\"><span class=\"std std-ref\">Hacheurs de mots de passe intégrés</span></a> pour le nom d’algorithme de chaque hacheur.</p>\n</dd></dl>\n\n<dl class=\"py function\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.hashers.make_password\">\n<span class=\"sig-name descname\"><span class=\"pre\">make_password</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">password</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">salt</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">None</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">hasher</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">'default'</span></span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.hashers.make_password\"><span class=\"visually-hidden\">Lien vers cette définition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>Crée une empreinte de mot de passe au format utilisé par cette application. Elle demande un paramètre obligatoire : le mot de passe en clair (chaîne ou octets). Il est aussi possible de fournir un sel et un algorithme de hachage à utiliser, si vous ne souhaitez pas utiliser les valeurs par défaut (première ligne du réglage <code class=\"docutils literal notranslate\"><span class=\"pre\">PASSWORD_HASHERS</span></code>). Voir <a class=\"reference internal\" href=\"#auth-included-hashers\"><span class=\"std std-ref\">Hacheurs de mots de passe intégrés</span></a> pour le nom d’algorithme de chaque hacheur de mots de passe. Si le paramètre du mot de passe vaut <code class=\"docutils literal notranslate\"><span class=\"pre\">None</span></code>, un mot de passe inutilisable est renvoyé (un mot de passe qui fera que <a class=\"reference internal\" href=\"#django.contrib.auth.hashers.check_password\" title=\"django.contrib.auth.hashers.check_password\"><code class=\"xref py py-func docutils literal notranslate\"><span class=\"pre\">check_password()</span></code></a> renvoie toujours <code class=\"docutils literal notranslate\"><span class=\"pre\">False</span></code>) .</p>\n</dd></dl>\n\n<dl class=\"py function\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.hashers.is_password_usable\">\n<span class=\"sig-name descname\"><span class=\"pre\">is_password_usable</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">encoded_password</span></span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.hashers.is_password_usable\"><span class=\"visually-hidden\">Lien vers cette définition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>Renvoie <code class=\"docutils literal notranslate\"><span class=\"pre\">False</span></code> si le mot de passe a été produit par <a class=\"reference internal\" href=\"/fr/5.2/ref/contrib/auth/#django.contrib.auth.models.User.set_unusable_password\" title=\"django.contrib.auth.models.User.set_unusable_password\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">User.set_unusable_password()</span></code></a>.</p>\n</dd></dl>\n\n</section>\n<section id=\"module-django.contrib.auth.password_validation\">\n<span id=\"id3\"></span><span id=\"password-validation\"></span><h2>Validation des mots de passe<a class=\"heading-anchor\" href=\"#module-django.contrib.auth.password_validation\"><span class=\"visually-hidden\">Lien vers cette rubrique</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>Les utilisateurs choisissent souvent des mots de passe faibles. Pour aider à résoudre ce problème, Django offre une validation des mots de passe à options. Vous pouvez configurer plusieurs validateurs de mots de passe en parallèle. Quelques-uns sont inclus dans Django, mais vous pouvez aussi écrire votre propre validateur.</p>\n<p>Chaque validateur de mot de passe doit fournir un texte d’aide pour expliquer les exigences aux utilisateurs, la validation d’un mot de passe donné et un message d’erreur si le mot de passe ne respecte pas les exigences. Facultativement, il peut définir une fonction de rappel afin d’être averti lorsque le mot de passe d’un utilisateur a été changé. Les validateurs peuvent également proposer des réglages facultatifs pour spécialiser leur comportement.</p>\n<p>La validation est contrôlée par le réglage <a class=\"reference internal\" href=\"/fr/5.2/ref/settings/#std-setting-AUTH_PASSWORD_VALIDATORS\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">AUTH_PASSWORD_VALIDATORS</span></code></a>. La liste de ce réglage est vide par défaut, ce qui signifie qu’aucun validateur n’est appliqué. Dans les nouveaux projets créés par le modèle <a class=\"reference internal\" href=\"/fr/5.2/ref/django-admin/#django-admin-startproject\"><code class=\"xref std std-djadmin docutils literal notranslate\"><span class=\"pre\">startproject</span></code></a> par défaut, un ensemble de validateurs sont activés.</p>\n<p>Par défaut, les validateurs sont utilisés dans les formulaires pour réinitialiser ou modifier les mots de passe, ainsi que dans les commandes d’administration <a class=\"reference internal\" href=\"/fr/5.2/ref/django-admin/#django-admin-createsuperuser\"><code class=\"xref std std-djadmin docutils literal notranslate\"><span class=\"pre\">createsuperuser</span></code></a> et <a class=\"reference internal\" href=\"/fr/5.2/ref/django-admin/#django-admin-changepassword\"><code class=\"xref std std-djadmin docutils literal notranslate\"><span class=\"pre\">changepassword</span></code></a>. Les validateurs ne sont pas appliqués au niveau des modèles, par exemple dans <code class=\"docutils literal notranslate\"><span class=\"pre\">User.objects.create_user()</span></code> et <code class=\"docutils literal notranslate\"><span class=\"pre\">create_superuser()</span></code>, parce qu’à ce niveau ce sont les développeurs et non les utilisateurs qui interagissent avec Django et également parce que la validation des modèles n’est pas automatiquement exécutée dans le contexte de la création de modèles.</p>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">Note</p>\n<p>La validation des mots de passe peut éviter l’emploi de différents types de mots de passe faibles. Cependant, même si un mot de passe est validé par tous les validateurs, cela ne garantit pas forcément un mot de passe solide. Il existe de nombreux facteurs affaiblissant la solidité d’un mot de passe et qui ne peuvent pas être détectés par les validateurs de mots de passe même les plus avancés.</p>\n</aside>\n<section id=\"enabling-password-validation\">\n<h3>Activation de la validation des mots de passe<a class=\"heading-anchor\" href=\"#enabling-password-validation\"><span class=\"visually-hidden\">Lien vers cette rubrique</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>La validation des mots de passe est configurée par le réglage <a class=\"reference internal\" href=\"/fr/5.2/ref/settings/#std-setting-AUTH_PASSWORD_VALIDATORS\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">AUTH_PASSWORD_VALIDATORS</span></code></a>:</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"n\">AUTH_PASSWORD_VALIDATORS</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n    <span class=\"p\">{</span>\n        <span class=\"s2\">&quot;NAME&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;django.contrib.auth.password_validation.UserAttributeSimilarityValidator&quot;</span><span class=\"p\">,</span>\n    <span class=\"p\">},</span>\n    <span class=\"p\">{</span>\n        <span class=\"s2\">&quot;NAME&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;django.contrib.auth.password_validation.MinimumLengthValidator&quot;</span><span class=\"p\">,</span>\n        <span class=\"s2\">&quot;OPTIONS&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n            <span class=\"s2\">&quot;min_length&quot;</span><span class=\"p\">:</span> <span class=\"mi\">9</span><span class=\"p\">,</span>\n        <span class=\"p\">},</span>\n    <span class=\"p\">},</span>\n    <span class=\"p\">{</span>\n        <span class=\"s2\">&quot;NAME&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;django.contrib.auth.password_validation.CommonPasswordValidator&quot;</span><span class=\"p\">,</span>\n    <span class=\"p\">},</span>\n    <span class=\"p\">{</span>\n        <span class=\"s2\">&quot;NAME&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;django.contrib.auth.password_validation.NumericPasswordValidator&quot;</span><span class=\"p\">,</span>\n    <span class=\"p\">},</span>\n<span class=\"p\">]</span>\n</code></pre></div>\n<p>Cet exemple active les quatre validateurs intégrés :</p>\n<ul class=\"simple\">\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">UserAttributeSimilarityValidator</span></code>, qui vérifie la similitude entre le mot de passe et certains attributs de l’utilisateur.</p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">MinimumLengthValidator</span></code>, qui vérifie la longueur minimale du mot de passe. Ce validateur est configuré avec une option personnalisée : il exige une longueur minimale de 9 caractères, au lieu des 8 par défaut.</p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">CommonPasswordValidator</span></code>, qui vérifie si le mot de passe se trouve dans une liste de mots de passe courants. Par défaut, cette comparaison se fait avec une liste de 20’000 mots de passe courants.</p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">NumericPasswordValidator</span></code>, qui vérifie que le mot de passe n’est pas entièrement numérique.</p></li>\n</ul>\n<p>Pour <code class=\"docutils literal notranslate\"><span class=\"pre\">UserAttributeSimilarityValidator</span></code> et <code class=\"docutils literal notranslate\"><span class=\"pre\">CommonPasswordValidator</span></code>, nous utilisons les réglages par défaut dans cet exemple. <code class=\"docutils literal notranslate\"><span class=\"pre\">NumericPasswordValidator</span></code> ne contient pas de réglages.</p>\n<p>Les textes d’aide et les messages d’erreur des validateurs de mots de passe sont toujours renvoyés dans l’ordre de leur apparition dans <a class=\"reference internal\" href=\"/fr/5.2/ref/settings/#std-setting-AUTH_PASSWORD_VALIDATORS\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">AUTH_PASSWORD_VALIDATORS</span></code></a>.</p>\n</section>\n<section id=\"included-validators\">\n<span id=\"included-password-validators\"></span><h3>Validateurs intégrés<a class=\"heading-anchor\" href=\"#included-validators\"><span class=\"visually-hidden\">Lien vers cette rubrique</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>Django fournit quatre validateurs intégrés :</p>\n<dl class=\"py class\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.password_validation.MinimumLengthValidator\">\n<em class=\"property\"><span class=\"k\"><span class=\"pre\">class</span></span><span class=\"w\"> </span></em><span class=\"sig-name descname\"><span class=\"pre\">MinimumLengthValidator</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">min_length</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">8</span></span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.password_validation.MinimumLengthValidator\"><span class=\"visually-hidden\">Lien vers cette définition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>Valide une longueur minimale des mots de passe. Cette longueur minimale peut être personnalisée avec le paramètre <code class=\"docutils literal notranslate\"><span class=\"pre\">min_length</span></code>.</p>\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.password_validation.MinimumLengthValidator.get_error_message\">\n<span class=\"sig-name descname\"><span class=\"pre\">get_error_message</span></span><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.password_validation.MinimumLengthValidator.get_error_message\"><span class=\"visually-hidden\">Lien vers cette définition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><aside class=\"version-note version-added\" data-version=\"5.2\">\n<p class=\"version-note-title\">New in Django 5.2</p></aside>\n<p>Un point d’accès pour personnaliser le message d’erreur <code class=\"docutils literal notranslate\"><span class=\"pre\">ValidationError</span></code>. La valeur par défaut est <code class=\"docutils literal notranslate\"><span class=\"pre\">&quot;Ce</span> <span class=\"pre\">mot</span> <span class=\"pre\">de</span> <span class=\"pre\">passe</span> <span class=\"pre\">est</span> <span class=\"pre\">trop</span> <span class=\"pre\">court.</span> <span class=\"pre\">Il</span> <span class=\"pre\">doit</span> <span class=\"pre\">contenir</span> <span class=\"pre\">au</span> <span class=\"pre\">moins</span> <span class=\"pre\">&lt;min_length&gt;</span> <span class=\"pre\">caractères.&quot;</span></code>.</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.password_validation.MinimumLengthValidator.get_help_text\">\n<span class=\"sig-name descname\"><span class=\"pre\">get_help_text</span></span><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.password_validation.MinimumLengthValidator.get_help_text\"><span class=\"visually-hidden\">Lien vers cette définition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>Un point d’accès pour personnaliser le texte d’aide du validateur. La valeur par défaut est <code class=\"docutils literal notranslate\"><span class=\"pre\">&quot;Votre</span> <span class=\"pre\">mot</span> <span class=\"pre\">de</span> <span class=\"pre\">passe</span> <span class=\"pre\">doit</span> <span class=\"pre\">contenir</span> <span class=\"pre\">au</span> <span class=\"pre\">moins</span> <span class=\"pre\">&lt;min_length&gt;</span> <span class=\"pre\">caractères.&quot;</span></code>.</p>\n</dd></dl>\n\n</dd></dl>\n\n<dl class=\"py class\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.password_validation.UserAttributeSimilarityValidator\">\n<em class=\"property\"><span class=\"k\"><span class=\"pre\">class</span></span><span class=\"w\"> </span></em><span class=\"sig-name descname\"><span class=\"pre\">UserAttributeSimilarityValidator</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">user_attributes</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">DEFAULT_USER_ATTRIBUTES</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">max_similarity</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">0.7</span></span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.password_validation.UserAttributeSimilarityValidator\"><span class=\"visually-hidden\">Lien vers cette définition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>Valide la non-similitude du mot de passe avec plusieurs attributs de l’utilisateur.</p>\n<p>Le paramètre <code class=\"docutils literal notranslate\"><span class=\"pre\">user_attributes</span></code> correspond à une itération de noms d’attributs utilisateur avec lesquels la comparaison sera effectuée. Si ce paramètre est omis, la liste par défaut contient : <code class=\"docutils literal notranslate\"><span class=\"pre\">'username',</span> <span class=\"pre\">'first_name',</span> <span class=\"pre\">'last_name',</span> <span class=\"pre\">'email'</span></code>. Les attributs qui n’existent pas sont ignorés.</p>\n<p>La similarité maximale autorisée des mots de passe peut être définie sur une échelle de 0,1 à 1,0 avec le paramètre <code class=\"docutils literal notranslate\"><span class=\"pre\">max_similarity</span></code>. Cette valeur est comparée au résultat de <a class=\"reference external\" href=\"https://docs.python.org/3/library/difflib.html#difflib.SequenceMatcher.quick_ratio\" title=\"(disponible dans Python v3.14)\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">difflib.SequenceMatcher.quick_ratio()</span></code></a>. Une valeur de 0,1 rejette les mots de passe qui ne sont pas clairement différents des attributs <code class=\"docutils literal notranslate\"><span class=\"pre\">user_attributes</span></code>, alors qu’une valeur de 1,0 ne rejette que les mots de passe qui sont identiques à une valeur d’attribut.</p>\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.password_validation.UserAttributeSimilarityValidator.get_error_message\">\n<span class=\"sig-name descname\"><span class=\"pre\">get_error_message</span></span><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.password_validation.UserAttributeSimilarityValidator.get_error_message\"><span class=\"visually-hidden\">Lien vers cette définition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><aside class=\"version-note version-added\" data-version=\"5.2\">\n<p class=\"version-note-title\">New in Django 5.2</p></aside>\n<p>Un point d’accès pour personnaliser le message d’erreur <code class=\"docutils literal notranslate\"><span class=\"pre\">ValidationError</span></code>. La valeur par défaut est <code class=\"docutils literal notranslate\"><span class=\"pre\">&quot;Le</span> <span class=\"pre\">mot</span> <span class=\"pre\">de</span> <span class=\"pre\">passe</span> <span class=\"pre\">est</span> <span class=\"pre\">trop</span> <span class=\"pre\">semblable</span> <span class=\"pre\">au</span> <span class=\"pre\">champ</span> <span class=\"pre\">&lt;attribut_utilisateur&gt;.&quot;</span></code>.</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.password_validation.UserAttributeSimilarityValidator.get_help_text\">\n<span class=\"sig-name descname\"><span class=\"pre\">get_help_text</span></span><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.password_validation.UserAttributeSimilarityValidator.get_help_text\"><span class=\"visually-hidden\">Lien vers cette définition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>Un point d’accès pour personnaliser le texte d’aide du validateur. La valeur par défaut est <code class=\"docutils literal notranslate\"><span class=\"pre\">&quot;Votre</span> <span class=\"pre\">mot</span> <span class=\"pre\">de</span> <span class=\"pre\">passe</span> <span class=\"pre\">ne</span> <span class=\"pre\">peut</span> <span class=\"pre\">pas</span> <span class=\"pre\">trop</span> <span class=\"pre\">ressembler</span> <span class=\"pre\">à</span> <span class=\"pre\">vos</span> <span class=\"pre\">autres</span> <span class=\"pre\">informations</span> <span class=\"pre\">personnelles.&quot;</span></code>.</p>\n</dd></dl>\n\n</dd></dl>\n\n<dl class=\"py class\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.password_validation.CommonPasswordValidator\">\n<em class=\"property\"><span class=\"k\"><span class=\"pre\">class</span></span><span class=\"w\"> </span></em><span class=\"sig-name descname\"><span class=\"pre\">CommonPasswordValidator</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">password_list_path</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">DEFAULT_PASSWORD_LIST_PATH</span></span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.password_validation.CommonPasswordValidator\"><span class=\"visually-hidden\">Lien vers cette définition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>Valide que le mot de passe ne correspond pas à un mot de passe courant. Le mot de passe est converti en minuscules (pour effectuer une comparaison insensible à la casse) puis est comparé à une liste de 20’000 mots de passe courants créée par <a class=\"reference external\" href=\"https://gist.github.com/roycewilliams/226886fd01572964e1431ac8afc999ce\">Royce Williams</a>.</p>\n<p><code class=\"docutils literal notranslate\"><span class=\"pre\">password_list_path</span></code> peut contenir un chemin vers un fichier personnalisé de mots de passe courants. Ce fichier doit contenir un mot de passe en minuscules par ligne et peut être soit compressé gzip, soit du texte pur.</p>\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.password_validation.CommonPasswordValidator.get_error_message\">\n<span class=\"sig-name descname\"><span class=\"pre\">get_error_message</span></span><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.password_validation.CommonPasswordValidator.get_error_message\"><span class=\"visually-hidden\">Lien vers cette définition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><aside class=\"version-note version-added\" data-version=\"5.2\">\n<p class=\"version-note-title\">New in Django 5.2</p></aside>\n<p>Un point d’accès pour personnaliser le message d’erreur <code class=\"docutils literal notranslate\"><span class=\"pre\">ValidationError</span></code>. La valeur par défaut est <code class=\"docutils literal notranslate\"><span class=\"pre\">&quot;Ce</span> <span class=\"pre\">mot</span> <span class=\"pre\">de</span> <span class=\"pre\">passe</span> <span class=\"pre\">est</span> <span class=\"pre\">trop</span> <span class=\"pre\">courant.&quot;</span></code>.</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.password_validation.CommonPasswordValidator.get_help_text\">\n<span class=\"sig-name descname\"><span class=\"pre\">get_help_text</span></span><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.password_validation.CommonPasswordValidator.get_help_text\"><span class=\"visually-hidden\">Lien vers cette définition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>Un point d’accès pour personnaliser le texte d’aide du validateur. La valeur par défaut est <code class=\"docutils literal notranslate\"><span class=\"pre\">&quot;Votre</span> <span class=\"pre\">mot</span> <span class=\"pre\">de</span> <span class=\"pre\">passe</span> <span class=\"pre\">ne</span> <span class=\"pre\">peut</span> <span class=\"pre\">pas</span> <span class=\"pre\">être</span> <span class=\"pre\">un</span> <span class=\"pre\">mot</span> <span class=\"pre\">de</span> <span class=\"pre\">passe</span> <span class=\"pre\">couramment</span> <span class=\"pre\">utilisé.&quot;</span></code>.</p>\n</dd></dl>\n\n</dd></dl>\n\n<dl class=\"py class\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.password_validation.NumericPasswordValidator\">\n<em class=\"property\"><span class=\"k\"><span class=\"pre\">class</span></span><span class=\"w\"> </span></em><span class=\"sig-name descname\"><span class=\"pre\">NumericPasswordValidator</span></span><a class=\"heading-anchor\" href=\"#django.contrib.auth.password_validation.NumericPasswordValidator\"><span class=\"visually-hidden\">Lien vers cette définition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>Vérifie que le mot de passe n’est pas entièrement numérique.</p>\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.password_validation.NumericPasswordValidator.get_error_message\">\n<span class=\"sig-name descname\"><span class=\"pre\">get_error_message</span></span><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.password_validation.NumericPasswordValidator.get_error_message\"><span class=\"visually-hidden\">Lien vers cette définition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><aside class=\"version-note version-added\" data-version=\"5.2\">\n<p class=\"version-note-title\">New in Django 5.2</p></aside>\n<p>Un point d’accès pour personnaliser le message d’erreur <code class=\"docutils literal notranslate\"><span class=\"pre\">ValidationError</span></code>. La valeur par défaut est <code class=\"docutils literal notranslate\"><span class=\"pre\">&quot;Ce</span> <span class=\"pre\">mot</span> <span class=\"pre\">de</span> <span class=\"pre\">passe</span> <span class=\"pre\">est</span> <span class=\"pre\">entièrement</span> <span class=\"pre\">numérique.&quot;</span></code>.</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.password_validation.NumericPasswordValidator.get_help_text\">\n<span class=\"sig-name descname\"><span class=\"pre\">get_help_text</span></span><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.password_validation.NumericPasswordValidator.get_help_text\"><span class=\"visually-hidden\">Lien vers cette définition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>Un point d’accès pour personnaliser le texte d’aide du validateur. La valeur par défaut est <code class=\"docutils literal notranslate\"><span class=\"pre\">&quot;Votre</span> <span class=\"pre\">mot</span> <span class=\"pre\">de</span> <span class=\"pre\">passe</span> <span class=\"pre\">ne</span> <span class=\"pre\">peut</span> <span class=\"pre\">pas</span> <span class=\"pre\">être</span> <span class=\"pre\">entièrement</span> <span class=\"pre\">numérique.&quot;</span></code>.</p>\n</dd></dl>\n\n</dd></dl>\n\n</section>\n<section id=\"integrating-validation\">\n<h3>Intégration de la validation<a class=\"heading-anchor\" href=\"#integrating-validation\"><span class=\"visually-hidden\">Lien vers cette rubrique</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>Quelques fonctions dans <code class=\"docutils literal notranslate\"><span class=\"pre\">django.contrib.auth.password_validation</span></code> peuvent être appelées depuis vos propres formulaires ou votre code pour intégrer la validation des mots de passe. Cela peut être utile par exemple si vous utilisez des formulaires personnalisés pour la définition des mots de passe ou si vous écrivez des appels d’API permettant la définition de mots de passe.</p>\n<dl class=\"py function\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.password_validation.validate_password\">\n<span class=\"sig-name descname\"><span class=\"pre\">validate_password</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">password</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">user</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">None</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">password_validators</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">None</span></span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.password_validation.validate_password\"><span class=\"visually-hidden\">Lien vers cette définition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>Valide un mot de passe. Si tous les validateurs estiment que le mot de passe est valide, <code class=\"docutils literal notranslate\"><span class=\"pre\">None</span></code> sera renvoyé. Si un ou plusieurs validateurs rejettent le mot de passe, une exception <a class=\"reference internal\" href=\"/fr/5.2/ref/exceptions/#django.core.exceptions.ValidationError\" title=\"django.core.exceptions.ValidationError\"><code class=\"xref py py-exc docutils literal notranslate\"><span class=\"pre\">ValidationError</span></code></a> est produite contenant tous les messages d’erreur des validateurs.</p>\n<p>L’objet <code class=\"docutils literal notranslate\"><span class=\"pre\">user</span></code> est facultatif : s’il n’est pas présent, certains validateurs pourraient ne pas être capable de procéder à la validation et accepteront donc n’importe quel mot de passe.</p>\n</dd></dl>\n\n<dl class=\"py function\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.password_validation.password_changed\">\n<span class=\"sig-name descname\"><span class=\"pre\">password_changed</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">password</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">user</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">None</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">password_validators</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">None</span></span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.password_validation.password_changed\"><span class=\"visually-hidden\">Lien vers cette définition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>Informe tous les validateurs que le mot de passe a été changé. Cela peut être utilisé par certains validateurs, par exemple pour éviter de réutiliser un même mot de passe. Cette méthode doit être appelée après que le mot de passe a été modifié avec succès.</p>\n<p>Pour les sous-classes de <a class=\"reference internal\" href=\"/fr/5.2/topics/auth/customizing/#django.contrib.auth.models.AbstractBaseUser\" title=\"django.contrib.auth.models.AbstractBaseUser\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">AbstractBaseUser</span></code></a>, le champ mot de passe sera marqué « dirty » lors de l’appel à <a class=\"reference internal\" href=\"/fr/5.2/topics/auth/customizing/#django.contrib.auth.models.AbstractBaseUser.set_password\" title=\"django.contrib.auth.models.AbstractBaseUser.set_password\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">set_password()</span></code></a> qui déclenche un appel à <code class=\"docutils literal notranslate\"><span class=\"pre\">password_changed()</span></code> après l’enregistrement de l’utilisateur.</p>\n</dd></dl>\n\n<dl class=\"py function\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.password_validation.password_validators_help_texts\">\n<span class=\"sig-name descname\"><span class=\"pre\">password_validators_help_texts</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">password_validators</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">None</span></span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.password_validation.password_validators_help_texts\"><span class=\"visually-hidden\">Lien vers cette définition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>Renvoie une liste des textes d’aide de tous les validateurs. Ceux-ci expliquent les exigences du mot de passe aux utilisateurs.</p>\n</dd></dl>\n\n<dl class=\"py function\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.password_validation.password_validators_help_text_html\">\n<span class=\"sig-name descname\"><span class=\"pre\">password_validators_help_text_html</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">password_validators</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">None</span></span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.password_validation.password_validators_help_text_html\"><span class=\"visually-hidden\">Lien vers cette définition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>Renvoie une chaîne HTML avec tous les textes d’aide dans une balise <code class=\"docutils literal notranslate\"><span class=\"pre\">&lt;ul&gt;</span></code>. C’est pratique lors de l’ajout de la validation des mots de passe dans les formulaires, car cela permet de passer directement ce contenu au paramètre <code class=\"docutils literal notranslate\"><span class=\"pre\">help_text</span></code> d’un champ de formulaire.</p>\n</dd></dl>\n\n<dl class=\"py function\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.password_validation.get_password_validators\">\n<span class=\"sig-name descname\"><span class=\"pre\">get_password_validators</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">validator_config</span></span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.password_validation.get_password_validators\"><span class=\"visually-hidden\">Lien vers cette définition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>Renvoie un ensemble d’objets validateurs en fonction du paramètre <code class=\"docutils literal notranslate\"><span class=\"pre\">validator_config</span></code>. Par défaut, toutes les fonctions utilisent les validateurs définis dans <a class=\"reference internal\" href=\"/fr/5.2/ref/settings/#std-setting-AUTH_PASSWORD_VALIDATORS\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">AUTH_PASSWORD_VALIDATORS</span></code></a>, mais en appelant cette fonction avec un ensemble différent de validateurs et en passant le résultat dans le paramètre <code class=\"docutils literal notranslate\"><span class=\"pre\">password_validators</span></code> des autres fonctions, c’est cet ensemble de validateurs qui sera alors utilisé. C’est pratique lorsqu’un certain groupe de validateurs s’applique à la majorité des scénarios, mais qu’il existe certains cas qui demandent un autre ensemble. Si vous utilisez toujours les mêmes validateurs, cette fonction n’est pas utile car la configuration provenant de <a class=\"reference internal\" href=\"/fr/5.2/ref/settings/#std-setting-AUTH_PASSWORD_VALIDATORS\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">AUTH_PASSWORD_VALIDATORS</span></code></a> est utilisée par défaut.</p>\n<p>La structure de <code class=\"docutils literal notranslate\"><span class=\"pre\">validator_config</span></code> est identique à la structure de <a class=\"reference internal\" href=\"/fr/5.2/ref/settings/#std-setting-AUTH_PASSWORD_VALIDATORS\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">AUTH_PASSWORD_VALIDATORS</span></code></a>. La valeur renvoyée par cette fonction peut être transmise dans le paramètre <code class=\"docutils literal notranslate\"><span class=\"pre\">password_validators</span></code> des fonctions présentées précédemment.</p>\n</dd></dl>\n\n<p>Notez que là où le mot de passe est passé en paramètre d’une de ces fonctions, il s’agit toujours du mot de passe en clair, pas de la version hachée.</p>\n</section>\n<section id=\"writing-your-own-validator\">\n<h3>Écriture de son propre validateur<a class=\"heading-anchor\" href=\"#writing-your-own-validator\"><span class=\"visually-hidden\">Lien vers cette rubrique</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>Si les validateurs intégrés à Django ne suffisent pas, vous pouvez écrire votre propre validateur de mot de passe. Les validateurs ont une interface assez restreinte. Elles doivent implémenter deux méthodes :</p>\n<ul class=\"simple\">\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">validate(self,</span> <span class=\"pre\">password,</span> <span class=\"pre\">user=None)</span></code>: valide un mot de passe. Renvoie <code class=\"docutils literal notranslate\"><span class=\"pre\">None</span></code> si le mot de passe est valide, ou génère une erreur <a class=\"reference internal\" href=\"/fr/5.2/ref/exceptions/#django.core.exceptions.ValidationError\" title=\"django.core.exceptions.ValidationError\"><code class=\"xref py py-exc docutils literal notranslate\"><span class=\"pre\">ValidationError</span></code></a> avec un message d’erreur si le mot de passe n’est pas valide. La méthode doit pouvoir gérer un utilisateur <code class=\"docutils literal notranslate\"><span class=\"pre\">user</span></code> valant <code class=\"docutils literal notranslate\"><span class=\"pre\">None</span></code>; si cela signifie que le validateur ne peut pas s’appliquer, renvoyez <code class=\"docutils literal notranslate\"><span class=\"pre\">None</span></code> pour signifier qu’il n’y a pas d’erreur.</p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">get_help_text()</span></code>: fournit un texte d’aide pour expliquer les exigences à l’utilisateur.</p></li>\n</ul>\n<p>Tout ce qui est dans <code class=\"docutils literal notranslate\"><span class=\"pre\">OPTIONS</span></code> dans <a class=\"reference internal\" href=\"/fr/5.2/ref/settings/#std-setting-AUTH_PASSWORD_VALIDATORS\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">AUTH_PASSWORD_VALIDATORS</span></code></a> pour votre validateur sera transmis au constructeur. Tous les paramètres du constructeur doivent posséder une valeur par défaut.</p>\n<p>Voici un exemple basique d’un validateur, avec un réglage facultatif :</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.core.exceptions</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">ValidationError</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.utils.translation</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">gettext</span> <span class=\"k\">as</span> <span class=\"n\">_</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">MinimumLengthValidator</span><span class=\"p\">:</span>\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"fm\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">min_length</span><span class=\"o\">=</span><span class=\"mi\">8</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">min_length</span> <span class=\"o\">=</span> <span class=\"n\">min_length</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">validate</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">password</span><span class=\"p\">,</span> <span class=\"n\">user</span><span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">password</span><span class=\"p\">)</span> <span class=\"o\">&lt;</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">min_length</span><span class=\"p\">:</span>\n            <span class=\"k\">raise</span> <span class=\"n\">ValidationError</span><span class=\"p\">(</span>\n                <span class=\"n\">_</span><span class=\"p\">(</span><span class=\"s2\">&quot;This password must contain at least </span><span class=\"si\">%(min_length)d</span><span class=\"s2\"> characters.&quot;</span><span class=\"p\">),</span>\n                <span class=\"n\">code</span><span class=\"o\">=</span><span class=\"s2\">&quot;password_too_short&quot;</span><span class=\"p\">,</span>\n                <span class=\"n\">params</span><span class=\"o\">=</span><span class=\"p\">{</span><span class=\"s2\">&quot;min_length&quot;</span><span class=\"p\">:</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">min_length</span><span class=\"p\">},</span>\n            <span class=\"p\">)</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">get_help_text</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"n\">_</span><span class=\"p\">(</span>\n            <span class=\"s2\">&quot;Your password must contain at least </span><span class=\"si\">%(min_length)d</span><span class=\"s2\"> characters.&quot;</span>\n            <span class=\"o\">%</span> <span class=\"p\">{</span><span class=\"s2\">&quot;min_length&quot;</span><span class=\"p\">:</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">min_length</span><span class=\"p\">}</span>\n        <span class=\"p\">)</span>\n</code></pre></div>\n<p>Vous pouvez aussi implémenter <code class=\"docutils literal notranslate\"><span class=\"pre\">password_changed(password,</span> <span class=\"pre\">user=None</span></code>), qui sera appelée à la suite d’un changement de mot de passe réussi. Cela peut être utilisé pour éviter la réutilisation de mot de passe, par exemple. Cependant, si vous décidez de stocker les mots de passe passés d’un utilisateur, vous ne devriez jamais le faire avec les mots de passe en clair.</p>\n</section>\n</section>","rootId":"password-management-in-django","toc":[{"title":"Stockage des mots de passe par Django","anchor":"how-django-stores-passwords","children":[{"title":"Utilisation de Argon2 avec Django","anchor":"using-argon2-with-django","children":[]},{"title":"Utilisation de bcrypt avec Django","anchor":"using-bcrypt-with-django","children":[]},{"title":"Utilisation de scrypt avec Django","anchor":"using-scrypt-with-django","children":[]},{"title":"Augmentation de l’entropie du sel","anchor":"increasing-the-salt-entropy","children":[]},{"title":"Augmentation du facteur travail","anchor":"increasing-the-work-factor","children":[{"title":"PBKDF2 et bcrypt","anchor":"pbkdf2-and-bcrypt","children":[]},{"title":"Argon2","anchor":"argon2","children":[]},{"title":"scrypt","anchor":"scrypt","children":[]}]},{"title":"Mise à niveau des mots de passe","anchor":"password-upgrading","children":[]},{"title":"Mise à jour des mots de passe sans exiger de connexion","anchor":"password-upgrading-without-requiring-a-login","children":[]},{"title":"Hacheurs de mots de passe intégrés","anchor":"included-hashers","children":[]},{"title":"Écriture de son propre algorithme de hachage","anchor":"writing-your-own-hasher","children":[]}]},{"title":"Gestion manuelle des mots de passe","anchor":"module-django.contrib.auth.hashers","children":[]},{"title":"Validation des mots de passe","anchor":"module-django.contrib.auth.password_validation","children":[{"title":"Activation de la validation des mots de passe","anchor":"enabling-password-validation","children":[]},{"title":"Validateurs intégrés","anchor":"included-validators","children":[]},{"title":"Intégration de la validation","anchor":"integrating-validation","children":[]},{"title":"Écriture de son propre validateur","anchor":"writing-your-own-validator","children":[]}]}],"breadcrumbs":[{"docname":"topics/index","title":"Utilisation de Django","url":"/fr/5.2/topics/"},{"docname":"topics/auth/index","title":"Authentification des utilisateurs dans Django","url":"/fr/5.2/topics/auth/"}],"prev":{"docname":"topics/auth/default","title":"Utilisation du système d’authentification de Django","url":"/fr/5.2/topics/auth/default/"},"next":{"docname":"topics/auth/customizing","title":"Personnalisation de l’authentification dans Django","url":"/fr/5.2/topics/auth/customizing/"},"formats":{"html":"/fr/5.2/topics/auth/passwords/","markdown":"/fr/5.2/topics/auth/passwords.md","json":"/fr/5.2/topics/auth/passwords.json"},"source":"https://github.com/django/django/blob/stable/5.2.x/docs/topics/auth/passwords.txt","official":"https://docs.djangoproject.com/fr/5.2/topics/auth/passwords/","inVersions":["6.1","6.0","5.2","5.1","5.0","4.2","4.1","4.0","3.2","3.1","3.0","2.2","2.1","2.0","1.11","1.10","1.9"],"inLocales":["en","sv","zh-hans","ga","fr","ja","id","it","pt-br","ko","es","el","pl"]}