---
title: "Personnalisation de l’authentification dans Django"
version: 2.0
locale: fr
source: https://docs.djangoproject.com/fr/2.0/topics/auth/customizing/
canonical: https://djangodocs.dev/fr/2.0/topics/auth/customizing/
---
# Personnalisation de l’authentification dans Django

L’authentification livrée avec Django est suffisante dans la plupart des cas, mais vous pouvez rencontrez des besoins qui ne sont pas couverts par la solution proposée par défaut. Afin de personnaliser l’authentification pour les besoins de vos projets, vous devez comprendre quels sont les points d’ancrage permettant d’étendre et de remplacer les composants du système de Django. Ce document fournit des détails sur la façon dont le système d’authentification peut être adapté.

Les [moteurs d’authentification](#authentication-backends) permettent d’adapter le système lorsque un nom d’utilisateur et un mot de passe stockés dans le modèle d’utilisateur doivent servir à authentifier l’utilisateur avec un autre service que celui par défaut de Django.

Vous pouvez donner des [permissions personnalisées](#custom-permissions) à vos modèles qui peuvent être vérifiées à travers le système d’autorisation de Django.

Vous pouvez [étendre](#extending-user) le modèle `User` par défaut ou le [substituer](#auth-custom-user) par un tout autre modèle personnalisé.

## Autres sources d’authentification

Dans certaines situations, il peut être nécessaire de se connecter à une autre source d’authentification, c’est-à-dire une autre source de noms d’utilisateur et de mots de passe ou d’autres méthodes d’authentification.

Par exemple, votre entreprise possède peut-être déjà une infrastructure LDAP stockant les noms d’utilisateur et mots de passe pour tous ses employés. Il serait fastidieux aussi bien pour l’administrateur réseau que pour les utilisateurs eux-mêmes de devoir gérer des comptes séparés dans LDAP et dans les applications basées sur Django.

Ainsi, pour faire face à ce genre de situations, le système d’authentification de Django vous permet de brancher d’autres sources d’authentification. Vous pouvez surcharger le système par défaut de Django basé sur la base de données ou vous pouvez utiliser le système par défaut en parallèle avec d’autres systèmes.

Consultez la [référence sur les moteurs d’authentification](/fr/2.0/ref/contrib/auth/#authentication-backends-reference) pour plus d’informations sur les moteurs d’authentification intégrés à Django.

### Définition de moteurs d’authentification

En arrière-plan, Django maintient une liste de « moteurs d’authentification » qu’il sollicite lors de l’authentification. Lorsque quelqu’un appelle [`django.contrib.auth.authenticate()`](/fr/2.0/topics/auth/default/#django.contrib.auth.authenticate) comme expliqué ci-dessus dans [Comment connecter un utilisateur](/fr/2.0/topics/auth/default/#how-to-log-a-user-in), Django tente une authentification avec chaque moteur d’authentification. Si la première méthode d’authentification échoue, Django essaie avec la deuxième et ainsi de suite jusqu’à ce que tous les moteurs aient été sollicités.

La liste des moteurs d’authentification à utiliser est définie dans le réglage [`AUTHENTICATION_BACKENDS`](/fr/2.0/ref/settings/#std-setting-AUTHENTICATION_BACKENDS). Il doit s’agir d’une liste de chemins Python vers des classes Python qui sont capables d’authentifier des utilisateurs. Ces classes peuvent se trouver n’importe où dans votre chemin Python.

Par défaut, [`AUTHENTICATION_BACKENDS`](/fr/2.0/ref/settings/#std-setting-AUTHENTICATION_BACKENDS) contient :

```
['django.contrib.auth.backends.ModelBackend']
```

Il s’agit du moteur d’authentification de base qui vérifie la base de données Django des utilisateurs et interroge les permissions intégrées. Il ne protège pas contre les attaques de force brute et n’utilise pas de mécanisme de « rate limiting » (restriction du nombre de tentatives dans le temps). Vous pouvez soit écrire votre propre mécanisme de restriction dans un moteur d’authentification personnalisé ou utiliser les mécanismes offerts par la plupart des serveurs Web.

L’ordre dans la liste [`AUTHENTICATION_BACKENDS`](/fr/2.0/ref/settings/#std-setting-AUTHENTICATION_BACKENDS) a son importance ; si le même nom d’utilisateur et mot de passe est valable dans plusieurs moteurs, Django s’arrête dès qu’un moteur a accepté les données d’authentification.

Si un moteur génère une exception [`PermissionDenied`](/fr/2.0/ref/exceptions/#django.core.exceptions.PermissionDenied), l’authentification échouera immédiatement. Django ne continue pas avec les moteurs suivants.

> **Note**
>
> Dès qu’un utilisateur s’est authentifié, Django mémorise le moteur utilisé pour authentifier cet utilisateur dans sa session ; il réutilise ensuite ce même moteur pour toute la durée de la session chaque fois qu’il est nécessaire d’accéder à l’utilisateur actuellement authentifié. Cela signifie en pratique que les sources d’authentification sont mises en cache par session et que si vous modifiez [`AUTHENTICATION_BACKENDS`](/fr/2.0/ref/settings/#std-setting-AUTHENTICATION_BACKENDS), vous devrez réinitialiser les données de sessions dans le cas où vous voulez forcer les utilisateurs à s’authentifier à nouveau en utilisant une autre méthode. Une façon simple de faire cela est d’exécuter `Session.objects.all().delete()`.

### Écriture d’un moteur d’authentification

Un moteur d’authentification est une classe qui implémente obligatoirement deux méthodes : `get_user(user_id)` et `authenticate(request, **credentials)`. Facultativement, elle peut aussi implémenter un ensemble de [méthodes d’autorisation](#authorization-methods) liées aux permissions.

La méthode `get_user` accepte un paramètre `user_id`, qui peut être un nom d’utilisateur, un identifiant de base de données ou toute autre valeur, mais qui doit représenter la clé primaire de votre objet utilisateur. Elle renvoie un objet utilisateur.

La méthode `authenticate` accepte un objet `request` et des données d’authentification en paramètre. La plupart du temps, elle ressemblera à ceci :

```
class MyBackend:
    def authenticate(self, request, username=None, password=None):
        # Check the username/password and return a user.
        ...
```

Mais elle pourrait aussi authentifier avec un jeton, comme ceci :

```
class MyBackend:
    def authenticate(self, request, token=None):
        # Check the token and return a user.
        ...
```

D’une manière ou d’une autre, `authenticate()` doit vérifier les données d’authentification qu’elle reçoit et, dans le cas où ces données sont valides, elle doit renvoyer un objet utilisateur correspondant à ces données. Dans le cas contraire, elle doit renvoyer `None`.

`request` est un objet [`HttpRequest`](/fr/2.0/ref/request-response/#django.http.HttpRequest) et peut valoir `None` s’il n’a pas été fourni à [`authenticate()`](/fr/2.0/topics/auth/default/#django.contrib.auth.authenticate) (laquelle le transmet au moteur d’authentification).

Le site d’administration de Django est étroitement couplé à [l’objet User](/fr/2.0/topics/auth/default/#user-objects) de Django. La meilleure façon de gérer cela est de créer un objet Django `User` pour chaque utilisateur existant dans votre moteur (par ex. dans votre annuaire LDAP, votre base de données SQL externe, etc.). Vous pouvez soit écrire un script pour le faire de manière anticipée, soit déléguer à votre méthode `authenticate` la création de l’objet `User` lors de chaque première connexion.

Voici un exemple de moteur qui s’authentifie en fonction de variables nom d’utilisateur et mot de passe définies dans votre fichier `settings.py` et crée un objet `User` de Django lors de la première authentification de l’utilisateur :

```
from django.conf import settings
from django.contrib.auth.hashers import check_password
from django.contrib.auth.models import User

class SettingsBackend:
    """
    Authenticate against the settings ADMIN_LOGIN and ADMIN_PASSWORD.

    Use the login name and a hash of the password. For example:

    ADMIN_LOGIN = 'admin'
    ADMIN_PASSWORD = 'pbkdf2_sha256$30000$Vo0VlMnkR4Bk$qEvtdyZRWTcOsCnI/oQ7fVOu1XAURIZYoOZ3iq8Dr4M='
    """

    def authenticate(self, request, username=None, password=None):
        login_valid = (settings.ADMIN_LOGIN == username)
        pwd_valid = check_password(password, settings.ADMIN_PASSWORD)
        if login_valid and pwd_valid:
            try:
                user = User.objects.get(username=username)
            except User.DoesNotExist:
                # Create a new user. There's no need to set a password
                # because only the password from settings.py is checked.
                user = User(username=username)
                user.is_staff = True
                user.is_superuser = True
                user.save()
            return user
        return None

    def get_user(self, user_id):
        try:
            return User.objects.get(pk=user_id)
        except User.DoesNotExist:
            return None
```

> **Changed in Django 1.11**
>
> Le paramètre `request` a été ajouté à `authenticate()`. La prise en charge des moteurs qui n’acceptent pas ce nouveau paramètre sera supprimée dans Django 2.1.

### Gestion des autorisations dans les moteurs personnalisés

Les moteurs d’authentification personnalisés peuvent fournir leurs propres permissions.

Le modèle utilisateur délègue les fonctions de consultation des permissions ([`get_group_permissions()`](/fr/2.0/ref/contrib/auth/#django.contrib.auth.models.User.get_group_permissions), [`get_all_permissions()`](/fr/2.0/ref/contrib/auth/#django.contrib.auth.models.User.get_all_permissions), [`has_perm()`](/fr/2.0/ref/contrib/auth/#django.contrib.auth.models.User.has_perm) et [`has_module_perms()`](/fr/2.0/ref/contrib/auth/#django.contrib.auth.models.User.has_module_perms)) à tout moteur d’authentification qui implémente ces fonctions.

Les permissions données à l’utilisateur sera un surensemble de toutes les permissions renvoyées par tous les moteurs. Cela signifie que Django accorde une permission à un utilisateur pour autant qu’au moins un moteur le permette.

Si un moteur génère une exception [`PermissionDenied`](/fr/2.0/ref/exceptions/#django.core.exceptions.PermissionDenied) dans [`has_perm()`](/fr/2.0/ref/contrib/auth/#django.contrib.auth.models.User.has_perm) ou [`has_module_perms()`](/fr/2.0/ref/contrib/auth/#django.contrib.auth.models.User.has_module_perms), l’autorisation échouera immédiatement et Django ne continuera pas avec les moteurs suivants.

Le moteur simple ci-dessus pourrait implémenter les permissions pour l’administrateur « magique » assez simplement :

```
class SettingsBackend:
    ...
    def has_perm(self, user_obj, perm, obj=None):
        return user_obj.username == settings.ADMIN_LOGIN
```

Cela accorde toutes les permissions à l’utilisateur dont l’accès a été accordé dans l’exemple précédent. Notez qu’en plus des mêmes paramètres passés aux fonctions associées à [`django.contrib.auth.models.User`](/fr/2.0/ref/contrib/auth/#id1), les fonctions du moteur d’authentification acceptent toutes en paramètre l’objet utilisateur, qui pourrait être l’utilisateur anonyme.

Une implémentation complète des autorisations se trouve dans la classe `ModelBackend` dans [django/contrib/auth/backends.py](https://github.com/django/django/blob/master/django/contrib/auth/backends.py), qui constitue le moteur par défaut et interroge la plupart du temps la table `auth_permission`. Si vous souhaitez définir un comportement personnalisé uniquement pour une partie de l’API des moteurs, vous pouvez profiter de l’héritage Python et hériter de `ModelBackend` au lieu de réécrire l’API complète dans votre propre moteur.

#### Autorisation pour les utilisateurs anonymes

Un utilisateur anonyme est un utilisateur que ne s’est pas authentifié, c’est-à-dire qu’il n’a fourni aucun détail d’authentification valide. Cependant, cela ne signifie pas forcément qu’il ne reçoit aucune autorisation. Au niveau le plus élémentaire, la plupart des sites Web autorisent les utilisateurs anonymes à naviguer sur la plupart des pages du site, et certains autorisent également l’envoi de commentaires, etc.

Le système de permissions de Django ne prévoit pas d’endroit où stocker des permissions pour les utilisateurs anonymes. Cependant, l’objet utilisateur transmis au moteur d’authentification peut être un objet [`django.contrib.auth.models.AnonymousUser`](/fr/2.0/ref/contrib/auth/#django.contrib.auth.models.AnonymousUser) permettant au moteur de définir un comportement d’autorisation spécifique aux utilisateurs anonymes. C’est particulièrement utile pour les auteurs d’applications réutilisables qui peuvent déléguer toutes les questions d’autorisations au moteur d’authentification, plutôt que, par exemple, d’exiger des réglages pour contrôler les droits d’accès anonymes.

#### Autorisation pour les utilisateurs inactifs

Un utilisateur inactif est un utilisateur dont le champ [`is_active`](/fr/2.0/ref/contrib/auth/#django.contrib.auth.models.User.is_active) est défini à `False`. Les moteurs d’authentification [`ModelBackend`](/fr/2.0/ref/contrib/auth/#django.contrib.auth.backends.ModelBackend) and [`RemoteUserBackend`](/fr/2.0/ref/contrib/auth/#django.contrib.auth.backends.RemoteUserBackend) interdisent à ces utilisateurs de s’authentifier. Si un modèle d’utilisateur personnalisé ne possède pas de champ [`is_active`](#django.contrib.auth.models.CustomUser.is_active), tous les utilisateurs seront autorisés à s’authentifier.

Vous pouvez utiliser [`AllowAllUsersModelBackend`](/fr/2.0/ref/contrib/auth/#django.contrib.auth.backends.AllowAllUsersModelBackend) ou [`AllowAllUsersRemoteUserBackend`](/fr/2.0/ref/contrib/auth/#django.contrib.auth.backends.AllowAllUsersRemoteUserBackend) si vous souhaitez permettre aux utilisateurs inactifs de s’authentifier.

La prise en charge des utilisateurs anonymes dans le système des permissions permet d’imaginer un scénario où les utilisateurs anonymes ont certaines permissions que les utilisateurs authentifiés inactifs n’ont pas.

N’oubliez pas de tester l’attribut `is_active` de l’utilisateur dans les méthodes de votre propre moteur de permissions.

#### Gestion des permissions sur les objets

Le système de permissions de Django pose les fondations pour des permissions sur les objets, même s’il n’existe pas d’implémentation concrète dans le cœur de Django. Cela signifie que le contrôle des permissions sur les objets renvoie toujours `False` ou une liste vide (selon le contrôle effectué). Un moteur d’authentification reçoit les paramètres nommés `obj` et `user_obj` pour chaque méthode d’autorisation liée aux objets et peut renvoyer les permissions au niveau des objets comme il convient.

## Permissions personnalisées

Pour créer des permissions personnalisées pour un objet modèle donné, utilisez l”[attribut Meta](/fr/2.0/topics/db/models/#meta-options) `permissions` du modèle\`.

Ce modèle d’exemple `Task` crée trois permissions personnalisées, c’est-à-dire des actions que les utilisateurs peuvent effectuer ou non avec les instances `Task`, spécifiquement à votre application :

```
class Task(models.Model):
    ...
    class Meta:
        permissions = (
            ("view_task", "Can see available tasks"),
            ("change_task_status", "Can change the status of tasks"),
            ("close_task", "Can remove a task by setting its status as closed"),
        )
```

La seule conséquence de ce code est la création de ces permissions supplémentaires lors du lancement de [`manage.py migrate`](/fr/2.0/ref/django-admin/#django-admin-migrate) (la fonction qui crée les permissions est connectée au signal [`post_migrate`](/fr/2.0/ref/signals/#django.db.models.signals.post_migrate)). Votre code a ensuite la charge de contrôler la valeur de ces permissions lorsqu’un utilisateur essaie d’accéder à la fonctionnalité fournie par l’application (affichage de tâches, modification de l’état des tâches, fermeture des tâches). En poursuivant sur l’exemple précédent, le code suivant contrôle si un utilisateur peut voir les tâches :

```
user.has_perm('app.view_task')
```

## Extension du modèle `User` existant

Il existe deux manières d’étendre le modèle [`User`](/fr/2.0/ref/contrib/auth/#id1) par défaut sans le substituer par votre propre modèle. Si les modifications requises sont purement comportementales et ne nécessitent pas de modifier ce qui est stocké dans la base de données, vous pouvez créer un [modèle mandataire](/fr/2.0/topics/db/models/#proxy-models) basé sur [`User`](/fr/2.0/ref/contrib/auth/#id1). Ceci expose toutes les fonctionnalités offertes par les modèles mandataires, y compris l’ordre de tri par défaut, les gestionnaires personnalisés ou les méthodes de modèle personnalisées.

Si vous souhaitez stocker des informations liées au modèle `User`, vous pouvez utiliser une relation [`OneToOneField`](/fr/2.0/ref/models/fields/#django.db.models.OneToOneField) vers un modèle contenant les champs correspondant aux informations supplémentaires. Ce modèle un-à-un est souvent appelé un modèle de profil, car il peut stocker des informations non liées à l’authentification au sujet d’un utilisateur du site. Par exemple, vous pouvez créer un modèle `Employee`:

```
from django.contrib.auth.models import User

class Employee(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    department = models.CharField(max_length=100)
```

En supposant qu’il existe un employé Fred Smith référencé à la fois par un modèle `User` et un modèle `Employee`, vous pouvez accéder aux informations liées en utilisant les conventions standards des modèles liés de Django :

```
>>> u = User.objects.get(username='fsmith')
>>> freds_department = u.employee.department
```

Pour ajouter les champs du modèle de profil à la page de l’utilisateur dans l’interface d’administration, définissez un [`InlineModelAdmin`](/fr/2.0/ref/contrib/admin/#django.contrib.admin.InlineModelAdmin) (pour cet exemple, nous utiliserons un [`StackedInline`](/fr/2.0/ref/contrib/admin/#django.contrib.admin.StackedInline)) dans le fichier `admin.py` de votre application et ajoutez-le à une classe `UserAdmin` qui sera enregistrée avec la classe [`User`](/fr/2.0/ref/contrib/auth/#id1):

```
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from django.contrib.auth.models import User

from my_user_profile_app.models import Employee

# Define an inline admin descriptor for Employee model
# which acts a bit like a singleton
class EmployeeInline(admin.StackedInline):
    model = Employee
    can_delete = False
    verbose_name_plural = 'employee'

# Define a new User admin
class UserAdmin(BaseUserAdmin):
    inlines = (EmployeeInline, )

# Re-register UserAdmin
admin.site.unregister(User)
admin.site.register(User, UserAdmin)
```

Ces modèles de profil n’ont aucune particularité, ce ne sont que des modèles Django qui possèdent un lien un-à-un avec un modèle d’utilisateur. En tant que tels, ils ne sont pas automatiquement créés lorsqu’un utilisateur est créé, mais il est possible de profiter du signal [`django.db.models.signals.post_save`](/fr/2.0/ref/signals/#django.db.models.signals.post_save) pour créer ou mettre à jour les modèles liés selon les besoins.

L’utilisation de modèles liés provoque des requêtes ou des jointures supplémentaires pour récupérer les données liées. En fonction de vos besoins, il peut être préférable d’utiliser un modèle d’utilisateur personnalisé possédant les champs liés supplémentaires. Cependant, des liens existants vers le modèle d’utilisateur par défaut dans les applications de votre projet pourraient justifier la charge supplémentaire sur la base de données.

## Substitution par un modèle `User` personnalisé

Certains types de projets ont des exigences en terme d’authentification pour lesquelles le modèle [`User`](/fr/2.0/ref/contrib/auth/#id1) intégré de Django ne convient pas toujours. Par exemple, certains sites préfèrent utiliser l’adresse électronique comme identifiant d’identification plutôt qu’un nom d’utilisateur.

Django permet de surcharger le modèle d’utilisateur par défaut en attribuant une valeur au réglage [`AUTH_USER_MODEL`](/fr/2.0/ref/settings/#std-setting-AUTH_USER_MODEL) se référant à un modèle personnalisé :

```
AUTH_USER_MODEL = 'myapp.MyUser'
```

Cette syntaxe pointée spécifie le nom de l’application Django (qui doit figurer dans [`INSTALLED_APPS`](/fr/2.0/ref/settings/#std-setting-INSTALLED_APPS)) et le nom du modèle Django que vous souhaitez utiliser comme modèle d’utilisateur.

### Utilisation d’un modèle d’utilisateur personnalisé au départ d’un projet

Si vous démarrez un nouveau projet, il est fortement recommandé de définir un modèle d’utilisateur personnalisé, même si le modèle [`User`](/fr/2.0/ref/contrib/auth/#id1) par défaut convient à vos besoins. Ce modèle se comportera comme le modèle d’utilisateur par défaut, mais vous serez en mesure de le personnaliser plus tard si le besoin devait se présenter :

```
from django.contrib.auth.models import AbstractUser

class User(AbstractUser):
    pass
```

N’oubliez pas de faire pointer [`AUTH_USER_MODEL`](/fr/2.0/ref/settings/#std-setting-AUTH_USER_MODEL) vers ce modèle. Faites-le avant de créer les premières migrations ou de lancer `manage.py migrate` pour la première fois.

De plus, inscrivez le modèle dans le fichier `admin.py` de l’application :

```
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from .models import User

admin.site.register(User, UserAdmin)
```

### Conversion vers un modèle d’utilisateur personnalisé en cours de projet

La modification de [`AUTH_USER_MODEL`](/fr/2.0/ref/settings/#std-setting-AUTH_USER_MODEL) après avoir créé les tables de base de données est notoirement plus difficile car cela affecte les clés étrangères et les relations plusieurs-à-plusieurs, par exemple.

Cette modification ne peut pas être automatisée et nécessite une intervention manuelle sur le schéma, en déplaçant les données depuis l’ancienne table des utilisateurs et peut-être même en réappliquant manuellement certaines migrations. Voir [#25313](https://code.djangoproject.com/ticket/25313) pour un aperçu des étapes à suivre.

En raison des limites de Django liées à la fonctionnalité de dépendance dynamique pour les modèles remplaçables à chaud, le modèle référencé par [`AUTH_USER_MODEL`](/fr/2.0/ref/settings/#std-setting-AUTH_USER_MODEL) doit être créé lors de la première migration de son application (généralement appelée `0001_initial`) ; sinon, vous aurez des problèmes de dépendances.

En outre, vous pouvez rencontrer une erreur `CircularDependencyError` lors de l’exécution des migrations lorsque Django n’est pas en mesure de briser automatiquement la boucle de dépendance en raison de la dépendance dynamique. Si vous rencontrez cette erreur, vous devez rompre la boucle en déplaçant les modèles dont dépend votre modèle d’utilisateur dans une deuxième migration (vous pouvez essayer de faire deux modèles normaux qui ont une clé `ForeignKey` l’un vers l’autre et voir comment `makemigrations` résout la dépendance circulaire si vous voulez voir comment cela se passe habituellement).

### Applications réutilisables et `AUTH_USER_MODEL`

Les applications réutilisables ne devraient pas implémenter de modèle d’utilisateur personnalisé. Un projet peut utiliser beaucoup d’applications, et deux applications réutilisables qui implémenteraient chacune un modèle d’utilisateur personnalisé ne pourraient pas être utilisées conjointement. Si vous avez besoin de stocker des informations liées aux utilisateurs dans une application, utilisez une liaison [`ForeignKey`](/fr/2.0/ref/models/fields/#django.db.models.ForeignKey) ou [`OneToOneField`](/fr/2.0/ref/models/fields/#django.db.models.OneToOneField) vers `settings.AUTH_USER_MODEL` comme expliqué ci-dessous.

### Références au modèle `User`

Si vous référencez directement [`User`](/fr/2.0/ref/contrib/auth/#id1) (par exemple dans une clé étrangère), votre code ne fonctionnera pas dans des projets où le réglage [`AUTH_USER_MODEL`](/fr/2.0/ref/settings/#std-setting-AUTH_USER_MODEL) a été défini à un autre modèle d’utilisateur.

#### `get_user_model()`

Au lieu de faire directement référence à  [`User`](/fr/2.0/ref/contrib/auth/#id1), il est préférable de référencer le modèle d’utilisateur en utilisant `django.contrib.auth.get_user_model()`. Cette méthode renvoie le modèle d’utilisateur actuellement actif, soit le modèle personnalisé s’il a été défini, soit [`User`](/fr/2.0/ref/contrib/auth/#id1).

Lorsque vous définissez une clé étrangère ou des relations plusieurs-à-plusieurs vers le modèle d’utilisateur, vous devriez indiquer le modèle personnalisé au moyen du réglage [`AUTH_USER_MODEL`](/fr/2.0/ref/settings/#std-setting-AUTH_USER_MODEL). Par exemple :

```
from django.conf import settings
from django.db import models

class Article(models.Model):
    author = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
    )
```

Lorsque vous vous connectez aux signaux envoyés par le modèle d’utilisateur, vous devriez indiquer le modèle personnalisé au moyen du réglage [`AUTH_USER_MODEL`](/fr/2.0/ref/settings/#std-setting-AUTH_USER_MODEL). Par exemple :

```
from django.conf import settings
from django.db.models.signals import post_save

def post_save_receiver(sender, instance, created, **kwargs):
    pass

post_save.connect(post_save_receiver, sender=settings.AUTH_USER_MODEL)
```

En règle générale, il est plus facile de se référer au modèle d’utilisateur avec le réglage [`AUTH_USER_MODEL`](/fr/2.0/ref/settings/#std-setting-AUTH_USER_MODEL) dans tout code exécuté au moment de l’importation. Cependant, il est aussi possible d’appeler `get_user_model()` pendant que Django est en train d’importer les modèles. Il est donc possible d’écrire `models.ForeignKey(get_user_model(), ...)`.

Si votre application est testée avec plusieurs modèles d’utilisateur, par exemple en utilisant `@override_settings(AUTH_USER_MODEL=...)`, et que vous conserviez en cache le résultat de `get_user_model()` dans une variable au niveau du module, il serait alors nécessaire d’écouter le signal  [`setting_changed`](/fr/2.0/ref/signals/#django.test.signals.setting_changed) pour réinitialiser le cache. Par exemple :

```
from django.apps import apps
from django.contrib.auth import get_user_model
from django.core.signals import setting_changed
from django.dispatch import receiver

@receiver(setting_changed)
def user_model_swapped(**kwargs):
    if kwargs['setting'] == 'AUTH_USER_MODEL':
        apps.clear_cache()
        from myapp import some_module
        some_module.UserModel = get_user_model()
```

> **Changed in Django 1.11**
>
> La possibilité d’appeler `get_user_model()` au stade de l’importation a été ajoutée.

### Indication d’une modèle d’utilisateur personnalisé

> **Considérations sur la conception des modèles**
>
> Réfléchissez sérieusement avant de déléguer les informations non directement liées à l’authentification au modèle d’utilisateur personnalisé.
>
> Il peut être préférable de stocker les informations d’utilisateur spécifiques à une application dans un modèle ayant une relation avec le modèle d’utilisateur. Cela permet à chaque application de définir ses propres exigences de données utilisateurs sans risquer d’entrer en conflit avec les autres applications. D’un autre côté, les requêtes qui auront besoin de ces informations liées devront effectuer une jointure de base de données, ce qui peut avoir une influence sur les performances.

Django s’attend à ce qu’un minimum d’exigences soient respectées dans les modèles d’utilisateur personnalisés.

Si vous utilisez le moteur d’authentification par défaut, le modèle doit alors comporter un seul champ unique pouvant être utilisé pour l’identification. Cela peut être un nom d’utilisateur, une adresse électronique ou tout autre attribut unique. Un champ de nom d’utilisateur non unique est autorisé si vous utilisez un moteur d’authentification personnalisé qui le prend en charge.

La manière la plus simple de construire un modèle d’utilisateur personnalisé en respectant les contraintes est d’hériter de [`AbstractBaseUser`](#django.contrib.auth.models.AbstractBaseUser). La classe [`AbstractBaseUser`](#django.contrib.auth.models.AbstractBaseUser) fournit l’implémentation de base d’un modèle d’utilisateur, y compris les mots de passe hachés et les jetons de réinitialisation des mots de passe. Vous devez ensuite fournir les détails d’implémentation critiques :

#### `class models.CustomUser`

#### `USERNAME_FIELD`

Une chaîne contenant le nom du champ du modèle d’utilisateur utilisé comme identifiant unique. C’est normalement quelque chose comme un nom d’utilisateur ou une adresse électronique, ou encore tout autre identifiant unique. Ce champ *doit* être unique (c’est-à-dire que `unique=True` doit apparaître dans sa définition), sauf dans le cas où vous utilisez un moteur d’authentification personnalisé qui sait gérer les noms d’utilisateur non uniques.

Dans l’exemple suivant, le champ `identifier` est utilisé comme champ d’identification :

```
class MyUser(AbstractBaseUser):
    identifier = models.CharField(max_length=40, unique=True)
    ...
    USERNAME_FIELD = 'identifier'
```

[`USERNAME_FIELD`](#django.contrib.auth.models.CustomUser.USERNAME_FIELD) prend dorénavant en charge les clés [`ForeignKey`](/fr/2.0/ref/models/fields/#django.db.models.ForeignKey). Comme il n’existe pas de moyen de passer des instances de modèles durant le dialogue avec [`createsuperuser`](/fr/2.0/ref/django-admin/#django-admin-createsuperuser), attendez-vous à ce que l’utilisateur saisisse la valeur de [`to_field`](/fr/2.0/ref/models/fields/#django.db.models.ForeignKey.to_field) (la clé primaire [`primary_key`](/fr/2.0/ref/models/fields/#django.db.models.Field.primary_key) par défaut) d’une instance existante.

#### `EMAIL_FIELD`

> **New in Django 1.11**

Une chaîne décrivant le nom du champ courriel du modèle `User`. Cette valeur est renvoyée par [`get_email_field_name()`](#django.contrib.auth.models.AbstractBaseUser.get_email_field_name).

#### `REQUIRED_FIELDS`

Une liste de noms de champs qui devront être renseignés lors de la création d’un utilisateur par la commande de gestion [`createsuperuser`](/fr/2.0/ref/django-admin/#django-admin-createsuperuser). La commande demandera de fournir une valeur pour chacun de ces champs. Cette liste doit contenir tous les champs pour lesquels l’attribut  [`blank`](/fr/2.0/ref/models/fields/#django.db.models.Field.blank) est `False` ou non défini, et peut inclure des champs supplémentaires pour lesquels vous souhaitez que l’utilisateur donne une valeur lorsqu’un utilisateur est créé de manière interactive. `REQUIRED_FIELDS` n’a aucun effet dans d’autres parties de Django, comme lors de la création d’un utilisateur par l’interface d’administration.

Par exemple, voici la définition partielle d’un modèle d’utilisateur définissant deux champs obligatoires, une date de naissance et une hauteur :

```
class MyUser(AbstractBaseUser):
    ...
    date_of_birth = models.DateField()
    height = models.FloatField()
    ...
    REQUIRED_FIELDS = ['date_of_birth', 'height']
```

> **Note**
>
> `REQUIRED_FIELDS` doit contenir tous les champs obligatoires de votre modèle d’utilisateur, mais ne doit *pas* contenir le champ `USERNAME_FIELD` ni le champ `password` car de toute façon, il faudra fournir des valeurs pour ces champs.

[`REQUIRED_FIELDS`](#django.contrib.auth.models.CustomUser.REQUIRED_FIELDS) prend dorénavant en charge les clés [`ForeignKey`](/fr/2.0/ref/models/fields/#django.db.models.ForeignKey). Comme il n’existe pas de moyen de passer des instances de modèles durant le dialogue avec [`createsuperuser`](/fr/2.0/ref/django-admin/#django-admin-createsuperuser), attendez-vous à ce que l’utilisateur saisisse la valeur de [`to_field`](/fr/2.0/ref/models/fields/#django.db.models.ForeignKey.to_field) (la clé primaire [`primary_key`](/fr/2.0/ref/models/fields/#django.db.models.Field.primary_key) par défaut) d’une instance existante.

#### `is_active`

Un attribut booléen indiquant si l’utilisateur est considéré comme « actif ». Cet attribut est fournit comme attribut de `AbstractBaseUser` et valant `True` par défaut. La manière dont vous allez l’implémenter dépendra des détails des moteurs d’authentification choisis. Consultez la documentation de l”[`attribut is_active`](/fr/2.0/ref/contrib/auth/#django.contrib.auth.models.User.is_active) du modèle d’utilisateur intégré pour plus de détails.

#### `get_full_name()`

Facultatif. Un identifiant formel plus long pour l’utilisateur comme par exemple son nom complet. Si implémenté, il apparaît avec le nom d’utilisateur dans l’historique d’objets dans [`django.contrib.admin`](/fr/2.0/ref/contrib/admin/#module-django.contrib.admin).

#### `get_short_name()`

Facultatif. Un identifiant informel court pour l’utilisateur comme par exemple son prénom. Si implémenté, il remplace le nom d’utilisateur dans la salutation de l’utilisateur dans l’en-tête du site [`django.contrib.admin`](/fr/2.0/ref/contrib/admin/#module-django.contrib.admin).

> **Changed in Django 2.0**
>
> Dans les précédentes versions, des sous-classes devaient obligatoirement implémenter `get_short_name()` et `get_full_name()` car les implémentations de `AbstractBaseUser` généraient `NotImplementedError`.

> **Importation de AbstractBaseUser**
>
> `AbstractBaseUser` et `BaseUserManager` peuvent être importés à partir de `django.contrib.auth.base_user` afin qu’ils puissent être importés sans devoir inclure `django.contrib.auth` dans [`INSTALLED_APPS`](/fr/2.0/ref/settings/#std-setting-INSTALLED_APPS).

Les méthodes et attributs suivants sont disponibles pour chaque sous-classe de [`AbstractBaseUser`](#django.contrib.auth.models.AbstractBaseUser):

#### `class models.AbstractBaseUser`

#### `get_username()`

Renvoie la valeur du champ spécifié dans `USERNAME_FIELD`.

#### `clean()`

Normalise le nom d’utilisateur en appelant [`normalize_username()`](#django.contrib.auth.models.AbstractBaseUser.normalize_username). Si vous surchargez cette méthode, prenez soin d’appeler `super()` pour conserver la normalisation.

#### `classmethod get_email_field_name()`

> **New in Django 1.11**

Renvoie le nom du champ courriel désigné par l’attribut [`EMAIL_FIELD`](#django.contrib.auth.models.CustomUser.EMAIL_FIELD). Si `EMAIL_FIELD` n’est pas renseigné, renvoie `'email'` par défaut.

#### `classmethod normalize_username(username)`

Applique la normalisation Unicode NFKC aux noms d’utilisateurs afin que des caractères visuellement identiques avec des points de code Unicode différents soient considérés identiques.

#### `is_authenticated`

Attribut en lecture seule qui vaut toujours `True` (contrairement à `AnonymousUser.is_authenticated` qui vaut toujours `False`). C’est une façon de savoir si l’utilisateur a été authentifié. Aucune permission n’est prise en compte et il n’y a pas de contrôle sur le drapeau `is_active` de l’utilisateur ou sur la validité de la session. Même si cet attribut est généralement consulté pour `request.user` afin de déterminer s’il a été défini par [`AuthenticationMiddleware`](/fr/2.0/ref/middleware/#django.contrib.auth.middleware.AuthenticationMiddleware) (représentant l’utilisateur actuellement connecté), vous devez savoir que cet attribut vaut `True` pour toute instance de [`User`](/fr/2.0/ref/contrib/auth/#id1).

#### `is_anonymous`

Attribut en lecture seule qui vaut toujours `False`. C’est une façon de différencier les objets [`User`](/fr/2.0/ref/contrib/auth/#id1) des objets [`AnonymousUser`](/fr/2.0/ref/contrib/auth/#django.contrib.auth.models.AnonymousUser). Généralement, il vaut mieux utiliser [`is_authenticated`](/fr/2.0/ref/contrib/auth/#django.contrib.auth.models.User.is_authenticated) que cet attribut.

#### `set_password(raw_password)`

Définit le mot de passe de l’utilisateur à la chaîne brute indiquée, en se chargeant du hachage du mot de passe. L’objet [`AbstractBaseUser`](#django.contrib.auth.models.AbstractBaseUser) n’est pas enregistré par cette méthode.

Lorsque `raw_password` vaut `None`, le mot de passe sera défini comme non utilisable, comme si on avait appelé [`set_unusable_password()`](#django.contrib.auth.models.AbstractBaseUser.set_unusable_password).

#### `check_password(raw_password)`

Renvoie `True` si la chaîne brute transmise est le mot de passe correct de cet utilisateur (cette méthode se charge du hachage du mot de passe en vue de la comparaison).

#### `set_unusable_password()`

Marque l’utilisateur comme n’ayant pas de mot de passe défini. Ce n’est pas la même chose que de définir une chaîne vide comme mot de passe. [`check_password()`](#django.contrib.auth.models.AbstractBaseUser.check_password) ne renvoie jamais `True` pour cet utilisateur. L’objet [`AbstractBaseUser`](#django.contrib.auth.models.AbstractBaseUser) n’est pas enregistré par cette méthode.

Cela peut être utile si le processus d’authentification de votre application se fait par une source externe existante telle qu’un annuaire LDAP.

#### `has_usable_password()`

Renvoie `False` si [`set_unusable_password()`](#django.contrib.auth.models.AbstractBaseUser.set_unusable_password) a été appelée pour cet utilisateur.

#### `get_session_auth_hash()`

Renvoie une empreinte HMAC du champ de mot de passe. Utilisé pour [Invalidation de session lors du changement de mot de passe](/fr/2.0/topics/auth/default/#session-invalidation-on-password-change).

[`AbstractUser`](#django.contrib.auth.models.AbstractUser) hérite de [`AbstractBaseUser`](#django.contrib.auth.models.AbstractBaseUser):

#### `class models.AbstractUser`

#### `clean()`

> **New in Django 1.11**

Normalise l’adresse électronique en appelant [`BaseUserManager.normalize_email()`](#django.contrib.auth.models.BaseUserManager.normalize_email). Si vous surchargez cette méthode, prenez soin d’appeler `super()` pour conserver la normalisation.

Il faudrait aussi défini un gestionnaire personnalisé pour votre modèle d’utilisateur. Si ce dernier définit les champs `username`, `email`, `is_staff`, `is_active`, `is_superuser`, `last_login` et `date_joined` comparables au modèle d’utilisateur par défaut de Django, vous pouvez simplement utiliser le gestionnaire [`UserManager`](/fr/2.0/ref/contrib/auth/#django.contrib.auth.models.UserManager) de Django. Cependant, si votre modèle d’utilisateur définit des champs différents, vous devrez définir un gestionnaire personnalisé héritant de [`BaseUserManager`](#django.contrib.auth.models.BaseUserManager) et fournissant deux méthodes supplémentaires :

#### `class models.CustomUserManager`

#### `create_user(*username_field*, password=None, \**other_fields)`

Le prototype de `create_user()` doit accepter en paramètre le champ nom d’utilisateur ainsi que tous les champs obligatoires. Par exemple, si votre modèle d’utilisateur utilise `email` comme champ nom d’utilisateur et que `date_of_birth` est un champ obligatoire, `create_user` devrait être définie ainsi :

```
def create_user(self, email, date_of_birth, password=None):
    # create user here
    ...
```

#### `create_superuser(*username_field*, password, \**other_fields)`

Le prototype de `create_superuser()` doit accepter en paramètre le champ nom d’utilisateur ainsi que tous les champs obligatoires. Par exemple, si votre modèle d’utilisateur utilise `email` comme champ nom d’utilisateur et que `date_of_birth` est un champ obligatoire, `create_superuser` devrait être définie ainsi :

```
def create_superuser(self, email, date_of_birth, password):
    # create superuser here
    ...
```

Au contraire de `create_user()`, `create_superuser()` *doit* exiger de l’appelant qu’il fournisse un mot de passe.

[`BaseUserManager`](#django.contrib.auth.models.BaseUserManager) fournit les méthodes utilitaires suivantes :

#### `class models.BaseUserManager`

#### `classmethod normalize_email(email)`

Normalise les adresses électroniques en transformant en minuscules la partie nom de domaine de l’adresse.

#### `get_by_natural_key(username)`

Récupère une instance utilisateur en utilisant le contenu du champ spécifié dans `USERNAME_FIELD`.

#### `make_random_password(length=10, allowed_chars='abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789')`

Renvoie un mot de passe aléatoire de la longueur indiquée et utilisant les caractères de la chaîne des caractères autorisés. Notez que la valeur par défaut de `allowed_chars` ne contient pas de lettres pouvant prêter à confusion, comme :

- `i`, `l`, `I` et `1` (i minuscule, L minuscule, i majuscule et le chiffre 1)
- `o`, `O` et `0` (o minuscule, o majuscule et zéro)

### Extension du modèle `User` par défaut de Django

Si le modèle [`User`](/fr/2.0/ref/contrib/auth/#id1) de Django vous convient entièrement et que vous voulez simplement ajouter quelques informations de profil supplémentaires, il suffit d’hériter de [`django.contrib.auth.models.AbstractUser`](#django.contrib.auth.models.AbstractUser) et d’ajouter vos propres champs de profil. Il est toutefois conseillé de créer un modèle séparé, comme indiqué dans la note « Considérations de conception des modèles » de [Indication d’une modèle d’utilisateur personnalisé](#specifying-custom-user-model). `AbstractUser` fournit une implémentation complète du modèle [`User`](/fr/2.0/ref/contrib/auth/#id1) par défaut sous forme de [modèle abstrait](/fr/2.0/topics/db/models/#abstract-base-classes).

### Utilisateurs personnalisés et formulaires d’authentification intégrés

Les [formulaires](/fr/2.0/topics/auth/default/#built-in-auth-forms) et les [vues](/fr/2.0/topics/auth/default/#built-in-auth-views) intégrés de Django ont certaines attentes à propos du modèle utilisateur avec lequel ils fonctionnent.

Les formulaires suivants sont compatibles avec toutes les sous-classes de [`AbstractBaseUser`](#django.contrib.auth.models.AbstractBaseUser):

- [`AuthenticationForm`](/fr/2.0/topics/auth/default/#django.contrib.auth.forms.AuthenticationForm): utilise le champ de nom d’utilisateur indiqué par [`USERNAME_FIELD`](#django.contrib.auth.models.CustomUser.USERNAME_FIELD).
- [`SetPasswordForm`](/fr/2.0/topics/auth/default/#django.contrib.auth.forms.SetPasswordForm)
- [`PasswordChangeForm`](/fr/2.0/topics/auth/default/#django.contrib.auth.forms.PasswordChangeForm)
- [`AdminPasswordChangeForm`](/fr/2.0/topics/auth/default/#django.contrib.auth.forms.AdminPasswordChangeForm)

Les formulaires suivants ont certaines attentes à propos du modèle d’utilisateur et peuvent être utilisés tels quels si ces attentes sont remplies :

- [`PasswordResetForm`](/fr/2.0/topics/auth/default/#django.contrib.auth.forms.PasswordResetForm): s’attend à ce que le modèle utilisateur possède un champ qui stocke l’adresse électronique de l’utilisateur et nommé selon la valeur renvoyée par [`get_email_field_name()`](#django.contrib.auth.models.AbstractBaseUser.get_email_field_name) (`email` par défaut). Ce champ doit pouvoir être utilisé pour identifier l’utilisateur. Le formulaire compte aussi sur la présence du champ booléen `is_active` pour empêcher les utilisateurs inactifs de réinitialiser leur mot de passe.

Pour finir, les formulaires suivants sont liés à la classe [`User`](/fr/2.0/ref/contrib/auth/#id1) et doivent être réécrits ou étendus pour fonctionner avec un modèle d’utilisateur personnalisé :

- [`UserCreationForm`](/fr/2.0/topics/auth/default/#django.contrib.auth.forms.UserCreationForm)
- [`UserChangeForm`](/fr/2.0/topics/auth/default/#django.contrib.auth.forms.UserChangeForm)

Si votre modèle d’utilisateur personnalisé est une simple sous-classe de `AbstractUser`, vous pouvez alors étendre ces formulaires de cette façon :

```
from django.contrib.auth.forms import UserCreationForm
from myapp.models import CustomUser

class CustomUserCreationForm(UserCreationForm):

    class Meta(UserCreationForm.Meta):
        model = CustomUser
        fields = UserCreationForm.Meta.fields + ('custom_field',)
```

### Utilisateurs personnalisés et  [`django.contrib.admin`](/fr/2.0/ref/contrib/admin/#module-django.contrib.admin)

Si vous souhaitez que votre modèle d’utilisateur personnalisé fonctionne également dans l’interface d’administration, celui-ci doit définir certains attributs et méthodes supplémentaires. Ces méthodes permettent au site d’administration de contrôler l’accès de l’utilisateur à son contenu :

#### `class models.CustomUser`

#### `is_staff`

Renvoie `True` si l’utilisateur est autorisé à accéder au site d’administration.

#### `is_active`

Renvoie `True` si le compte utilisateur est actuellement actif.

#### `has_perm(perm, obj=None):`

Renvoie `True` si l’utilisateur possède la permission indiquée. Si `obj` est transmis, la permission doit être vérifiée en relation avec une instance d’objet spécifique.

#### `has_module_perms(app_label):`

Renvoie `True` si l’utilisateur possède la permission d’accéder aux modèles de l’application indiquée.

Il sera aussi nécessaire d’inscrire le modèle d’utilisateur personnalisé à l’interface d’administration. Si votre modèle hérite de `django.contrib.auth.models.AbstractUser`, vous pouvez utiliser la classe existante de Django `django.contrib.auth.admin.UserAdmin`. Cependant, si votre modèle hérite de [`AbstractBaseUser`](#django.contrib.auth.models.AbstractBaseUser), vous devrez définir une classe `ModelAdmin` personnalisée. Il est possible d’hériter de la classe `django.contrib.auth.admin.UserAdmin`, mais il faudra alors surcharger toutes les définitions qui se référent à des champs de `django.contrib.auth.models.AbstractUser` et qui ne se trouvent pas dans votre classe d’utilisateur personnalisée.

### Utilisateurs personnalisés et permissions

Pour faciliter l’intégration du système des permissions de Django à votre propre classe d’utilisateur, Django propose [`PermissionsMixin`](#django.contrib.auth.models.PermissionsMixin). Il s’agit d’un modèle abstrait que vous pouvez ajouter à la hiérarchie de classes de votre modèle d’utilisateur et qui vous offre ainsi toutes les méthodes et les champs de base de données nécessaires pour la prise en charge du modèle des permissions de Django.

[`PermissionsMixin`](#django.contrib.auth.models.PermissionsMixin) contient les méthodes et attributs suivants :

#### `class models.PermissionsMixin`

#### `is_superuser`

Valeur booléenne. Indique que cet utilisateur possède toutes les permissions sans avoir besoin de les lui attribuer explicitement.

#### `get_group_permissions(obj=None)`

Renvoie l’ensemble des permissions (chaînes) que l’utilisateur obtient au travers des groupes auxquels il/elle appartient.

Si `obj` est transmis, ne renvoie que les permissions de groupe liées à cet objet spécifique.

#### `get_all_permissions(obj=None)`

Renvoie l’ensemble des permissions (chaînes) que l’utilisateur obtient directement ou au travers des groupes auxquels il appartient.

Si `obj` est transmis, ne renvoie que les permissions liées à cet objet spécifique.

#### `has_perm(perm, obj=None)`

Renvoie `True` si l’utilisateur possède la permission indiquée, où `perm` est au format `"<étiquette application>.<code permission>"` (voir [permissions](/fr/2.0/topics/auth/default/#topic-authorization)). Si l’utilisateur est inactif, cette méthode renvoie toujours `False`.

Si `obj` est transmis, cette méthode ne contrôle pas la permission au niveau du modèle, mais pour l’objet indiqué.

#### `has_perms(perm_list, obj=None)`

Renvoie `True` si l’utilisateur possède toutes les permissions indiquées, où chaque permission est au format `"<étiquette application>.<code permission>"`. Si l’utilisateur est inactif, cette méthode renvoie toujours `False`.

Si `obj` est transmis, cette méthode ne contrôle pas les permissions au niveau du modèle, mais pour l’objet indiqué.

#### `has_module_perms(package_name)`

Renvoie `True` si l’utilisateur possède au moins une permission dans le module indiqué (l’étiquette d’application Django). Si l’utilisateur est inactif, cette méthode renvoie toujours `False`.

> **PermissionsMixin et ModelBackend**
>
> Si vous n’intégrez pas [`PermissionsMixin`](#django.contrib.auth.models.PermissionsMixin) vous devez vous assurer de ne pas appeler les méthodes de permissions sur `ModelBackend`. `ModelBackend` s’attend à ce que certains champs soient disponibles dans votre modèle d’utilisateur. Si ce dernier ne fournit pas ces champs, vous obtiendrez des erreurs de base de données lorsque vous contrôlez les permissions.

### Utilisateurs personnalisés et modèles mandataires

Une limite connue des modèles d’utilisateur personnalisés est que leur installation casse tout modèle mandataire étendant le modèle [`User`](/fr/2.0/ref/contrib/auth/#id1). Les modèles mandataires doivent hériter d’une classe de base concrète ; en définissant un modèle d’utilisateur personnalisé, vous supprimez la capacité de Django à identifier de manière fiable la classe de base.

Si votre projet utilise des modèles mandataires, vous devez soit modifier ces modèles afin qu’ils étendent le modèle d’utilisateur utilisé dans votre projet, soit fusionner le comportement du modèle mandataire dans votre sous-classe de [`User`](/fr/2.0/ref/contrib/auth/#id1).

### Un exemple complet

Voici un exemple d’application d’utilisateur personnalisé compatible avec l’interface d’administration. Ce modèle d’utilisateur utilise une adresse électronique comme nom d’utilisateur et possède un champ date de naissance obligatoire ; il ne fournit aucun contrôle de permission, excepté un simple drapeau `admin` sur le compte utilisateur. Ce modèle est compatible avec tous les formulaires et les vues d’authentification intégrés, à l’exception des formulaires de création d’utilisateur. Cet exemple illustre la façon dont la plupart des composants interagissent, mais il ne s’agit pas de code pouvant être directement copié dans des projets en production.

Ce code pourrait être entièrement placé dans un fichier `models.py` d’une application d’authentification personnalisée :

```
from django.db import models
from django.contrib.auth.models import (
    BaseUserManager, AbstractBaseUser
)

class MyUserManager(BaseUserManager):
    def create_user(self, email, date_of_birth, password=None):
        """
        Creates and saves a User with the given email, date of
        birth and password.
        """
        if not email:
            raise ValueError('Users must have an email address')

        user = self.model(
            email=self.normalize_email(email),
            date_of_birth=date_of_birth,
        )

        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_superuser(self, email, date_of_birth, password):
        """
        Creates and saves a superuser with the given email, date of
        birth and password.
        """
        user = self.create_user(
            email,
            password=password,
            date_of_birth=date_of_birth,
        )
        user.is_admin = True
        user.save(using=self._db)
        return user

class MyUser(AbstractBaseUser):
    email = models.EmailField(
        verbose_name='email address',
        max_length=255,
        unique=True,
    )
    date_of_birth = models.DateField()
    is_active = models.BooleanField(default=True)
    is_admin = models.BooleanField(default=False)

    objects = MyUserManager()

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['date_of_birth']

    def __str__(self):
        return self.email

    def has_perm(self, perm, obj=None):
        "Does the user have a specific permission?"
        # Simplest possible answer: Yes, always
        return True

    def has_module_perms(self, app_label):
        "Does the user have permissions to view the app `app_label`?"
        # Simplest possible answer: Yes, always
        return True

    @property
    def is_staff(self):
        "Is the user a member of staff?"
        # Simplest possible answer: All admins are staff
        return self.is_admin
```

Puis, pour inscrire ce modèle d’utilisateur personnalisé dans l’administration de Django, le code suivant doit se trouver dans le fichier `admin.py` de l’application :

```
from django import forms
from django.contrib import admin
from django.contrib.auth.models import Group
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from django.contrib.auth.forms import ReadOnlyPasswordHashField

from customauth.models import MyUser

class UserCreationForm(forms.ModelForm):
    """A form for creating new users. Includes all the required
    fields, plus a repeated password."""
    password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
    password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)

    class Meta:
        model = MyUser
        fields = ('email', 'date_of_birth')

    def clean_password2(self):
        # Check that the two password entries match
        password1 = self.cleaned_data.get("password1")
        password2 = self.cleaned_data.get("password2")
        if password1 and password2 and password1 != password2:
            raise forms.ValidationError("Passwords don't match")
        return password2

    def save(self, commit=True):
        # Save the provided password in hashed format
        user = super().save(commit=False)
        user.set_password(self.cleaned_data["password1"])
        if commit:
            user.save()
        return user

class UserChangeForm(forms.ModelForm):
    """A form for updating users. Includes all the fields on
    the user, but replaces the password field with admin's
    password hash display field.
    """
    password = ReadOnlyPasswordHashField()

    class Meta:
        model = MyUser
        fields = ('email', 'password', 'date_of_birth', 'is_active', 'is_admin')

    def clean_password(self):
        # Regardless of what the user provides, return the initial value.
        # This is done here, rather than on the field, because the
        # field does not have access to the initial value
        return self.initial["password"]

class UserAdmin(BaseUserAdmin):
    # The forms to add and change user instances
    form = UserChangeForm
    add_form = UserCreationForm

    # The fields to be used in displaying the User model.
    # These override the definitions on the base UserAdmin
    # that reference specific fields on auth.User.
    list_display = ('email', 'date_of_birth', 'is_admin')
    list_filter = ('is_admin',)
    fieldsets = (
        (None, {'fields': ('email', 'password')}),
        ('Personal info', {'fields': ('date_of_birth',)}),
        ('Permissions', {'fields': ('is_admin',)}),
    )
    # add_fieldsets is not a standard ModelAdmin attribute. UserAdmin
    # overrides get_fieldsets to use this attribute when creating a user.
    add_fieldsets = (
        (None, {
            'classes': ('wide',),
            'fields': ('email', 'date_of_birth', 'password1', 'password2')}
        ),
    )
    search_fields = ('email',)
    ordering = ('email',)
    filter_horizontal = ()

# Now register the new UserAdmin...
admin.site.register(MyUser, UserAdmin)
# ... and, since we're not using Django's built-in permissions,
# unregister the Group model from admin.
admin.site.unregister(Group)
```

Finalement, définissez le modèle personnalisé comme modèle d’utilisateur par défaut dans votre projet au moyen du réglage [`AUTH_USER_MODEL`](/fr/2.0/ref/settings/#std-setting-AUTH_USER_MODEL) dans votre fichier `settings.py`:

```
AUTH_USER_MODEL = 'customauth.MyUser'
```
