<< précédentsuivant >>

Chapitre 12: Sessions, utilisateurs et enregistrement

C’est l’heure de la confidence: nous avons délibérement ignorés un aspect incroyablement important du développement web jusqu’à présent. À ce jour, nous avons considéré le trafic vers nos sites comme quelque chose de sans visage, telle une masse anonyme dévalant sur nos pages soigneusement conçues.

Ce n’est pas vrai, bien sure. Les navigateurs interrogeant nos sites cachent des humains (la plupart du temps, pour le moins). C’est quelquechose d’ignorer cela: internet est à son appogée lorsqu’il sert à connecter des personnes , pas des machines. Si nous voulons développer des sites vraiment convaincants, nous allons avoir à traiter avec les personnes derrière les navigateurs.

Malheureusement, ce n’est pas chose facile. HTTP est conçu pour être sans état - autrement dit, chaque requète arrive dans le vide. Il n’y a pas de persistence entre une requêt et la suivante, et nous ne pouvons compter sur une caracteristique d’une requête (addresse IP, agent utilisateur, etc.) pour s’assurer que des requêtes successivent proviennent de la même personne.

Dans ce chapitre vous apprendrez à gérer cet absence d’état. Nous démarrerons au plus bas niveau (avec les cookies), pour monter vers des outils de plus haut niveau pour gérer les sessions, les utilisateurs et les enregistrements.

Cookies

Les développeurs de navigateurs ont reconnu depuis belle lurette que l’abscence d’état dans HTTP pose un gros problème aux développeurs web, et c’est pourquoi naquirent les cookies. Un cookie est un morceau d’information que les navigateurs stockent au nom du serveur web. Chaque fois qu’un navigateur demande une page d’un certain serveur, celui-ci lui retourne le cookie qu’il a initialement reçu.

Jetons un oeil sur la façon dont cela fonctionne. Lorsque vous ouvrez un navigateur pour saisir google.com, votre navigateur envoi une requête HTTP à Google qui commence par quelque chose du genre:

GET / HTTP/1.1
Host: google.com
...

Lorsque Google répond, la réponse HTTP ressemble alors à cela:

HTTP/1.1 200 OK
Content-Type: text/html
Set-Cookie: PREF=ID=5b14f22bdaf1e81c:TM=1167000671:LM=1167000671;
            expires=Sun, 17-Jan-2038 19:14:07 GMT;
            path=/; domain=.google.com
Server: GWS/2.1
...

Remarquez l’en-tête Set-Cookie. Votre navigateur stockera la valeur de ce cookie (PREF=ID=5b14f22bdaf1e81c:TM=1167000671:LM=1167000671) et la fournira à Google à chaque fois que vous accéderez au site. Ainsi la prochaine fois que vous accéderez à Google, votre navigateur enverra une requête de ce genre:

GET / HTTP/1.1
Host: google.com
Cookie: PREF=ID=5b14f22bdaf1e81c:TM=1167000671:LM=1167000671
...

Google peut alors utiliser cette valeur de Cookie pour savoir que vous êtes bien la même personne que celle qui a accédé au site auparavant. Cette valeur peut être, par exemple, une clef dans une base de données qui enregistre les informations sur l’utilisateur. Google peut (et doit) l’utiliser pour afficher votre nom sur la page.

Obtenir et paramètrer les Cookies

Lorsque vous aurez à faire à la persistence sous Django, la plupart du temps vous voudrez utiliser les sessions de plus haut niveau ou les frameworks utilisateurs abordés un peu plus loin dans ce chapitre. Cependant, nous ferons une pause et regarderons comment lire et écrire les cookies à un bas niveau. Ceci doit vous aider à comprendre comment le reste des outils utilisés dans ce chapitre fonctionne réellement, et restera utile si vous devez un jour jouer directement avec ces cookies.

Lire les cookies qui sont déjà paramétrés est incroyablement simple. Chaque objet requête possède un objet COOKIES qui se comporte comme un dictionnaire; vous pouvez l’utiliser pour lire n’importe quel cookie que le navigateur a envoyé à la vue:

def show_color(request):
    if "favorite_color" in request.COOKIES:
        return HttpResponse("Your favorite color is %s" % \
            request.COOKIES["favorite_color"])
    else:
        return HttpResponse("You don't have a favorite
        color.")

Écrire des cookies est légèrement plus compliqué. Vous devez utiliser la méthode set_cookie() sur un objet HttpResponse. Voici un exemple qui paramètre le cookie favorite_color selon le paramètre GET:

def set_color(request):
    if "favorite_color" in request.GET:

        # Create an HttpResponse object...
        response = HttpResponse("Your favorite color is now
        %s" % \
            request.GET["favorite_color"])

        # ... and set a cookie on the response
        response.set_cookie("favorite_color", request.GET["favorite_color"])

        return response

    else:
        return HttpResponse("You didn't give a favorite
        color.")

Vous pouvez aussi transmettre un nombre d’arguments optionnels à response.set_cookie() qui contrôle l’aspect du cookie, comme le montre le tableau 12-1.

Table 12-1: options de cookie

Parametre Valeur par defaut Description
max_age None Durée (en secondes) de persistance du cookie. Si sa valeur est à None, le cookie persistera jusqu’à ce que le soit fermé.
expires None La date/heure d’expiration du cookie. Elle doit être au format "Wdy, DD-Mth-YY HH:MM:SS GMT". S’il est précisé, ce paramètre prévaut sur le paramètre max_age.
path "/"

Le préfix du chemin pour lequel ce cookie est valide. Les navigateurs transmettrons le cookie aux pages présentant ce préfixe, vous pouvez donc utiliser ce paramètre pour pour éviter que les cookies ne soient envoyé aux autres parties de votre site.

Ceci est particulièrement pratique lorsque vous ne contrôlez pas la racine du domaine de votre site.

domain None

Le domaine pour lequel ce cookie est valide. Vous pouvez utiliser ce paramètre pour paramétrer un cookie mutli-domaine. Par exemple, domain=".exemple.com" fixera un cookie qui est consultable par les domaines www.exemple.com, www2.exemple.com, et un.autre.sous.domaine.exemple.com.

Si ce paramètre est fixé à None, un cookie ne sera lisible que par le domaine qui l’a paramétré.

secure False Si fixé à True, ce paramètre indique au navigateur qu’il doit renvoyer ce cookie aux pages accessibles via HTTPS uniquement.

Les bienfaits des cookies

Vous avez peut être remarquez quelques problèmes potentiels avec la façon dont fonctionnent les cookies. Détaillons ceux parmis les plus importants:

  • le stockage des cookies est essentiellement volontaire; les navigateurs ne garantissent rien. En fait, tous les navigateurs proposent aux utilisateurs une politique pour accepter les cookies. Si vous voulez voire combien les cookies sont vitaux pour le web, essayez d’activer l’option «demander confirmation avant d’accepter les cookies».

    En dépis de leur usage quasi universel, les cookies se définnisent encore par leur manque de fiabilité. Ceci signifie que les développeurs doivent vérifier que l’utilisateur accepte les cookies avant de se baser sur ceux-ci.

    Plus important, vous ne devez jamais stocker des données importantes dans des cookies. Le web est plein d’histoires horribles de développeurs qui ont perdu des données stockées dans les cookies du navigateur et qui ont vu ces données purgées par le navigateur, pour une raison ou pour une autre.

  • Cookies (en particulier ceux n’étant pas transmis par HTTPS) ne sont pas sûres. Puisque les données HTTP sont envoyé en texte, les cookies sont extremement vulnérables aux attaques de type sniffeuses. Ce faisant, un attaquant sniffant les paquets peut intercepter un cookie et le lire. Cela signifie que vous ne devez jamais stocker des informations sensibles dans un cookie.

    Il existe même une attaque encore plus incidieuse, connue sous le nom de man-in-the-middle, où l’attaquant intercepte un cookie et l’utilise pour se substituer à un autre utilisateur. Le chapitre 19 aborde les attaques de cette nature en profondeur, et les façon de s’en prévenir.

  • Même les cookies provenant du destinataire prévu ne sont pas sûres. La plupart des navigateurs fournissent un moyen simple pour éditer le contenu individuel des cookies, sans compter sur les utilisateurs avertis qui peuvent toujours utiliser des outils tel que mechanize (http://wwwsearch.sourceforge.net/mechanize/) pour construire des requêtes HTTP à la main.

    Vous ne pouvez donc pas stocker des données dans les cookies qui peuvent être falsifiés. L’erreur canonique de ce scénario est de stocker quelque chose comme IsLoggedIn=1 dans un cookie lorsqu’un utilisateur se connecte. Vous seriez surpris par le nombre de sites qui font des erreurs de cette nature; une seconde est nécessaire pour tromper le système de sécurité de ces sites .

Le framework de sessions sous Django

Avec toutes ces limitations et ces failles de sécurité potentielles, il est évident que les cookies et les sessions persistantes sont des exemples de «points pénibles» dans le développement web. Bien sûr, l’objectif de Django étant d’être un «tueur de pénibilité» efficace, il est fournit avec un framework de sessions conçu pour lisser ces difficultés à votre place.

Ce framework de session vous permet de stocker et de récupérer des données arbitraires sur la base d’un visiteur pour un site. Il stocke les données du côté serveur et fait abstraction de l’envoie et de la réception des cookies. Les cookies utilisent seulement un ID de session haché - et non pas les données elles-mêmes - de façon à vous protéger de la plupart des problèmes courants avec les cookies.

Regardons comment activer les sessions et les utiliser dans les vues.

Activer les sessions

Les sessions sont implémentées via un morceau de middleware (voir le chapitre 15) ainsi que via un modèle Django. Pour activer les sessions, vous devrez suivre les étapes suivantes:

  1. Éditez votre paramètre MIDDLEWARE_CLASSES et assurez vous que MIDDLEWARE_CLASSES contient 'django.contrib.sessions.middleware.SessionMiddleware'.
  2. Assurez vous que 'django.contrib.sessions' soit présent dans votre paramètre INSTALLED_APPS (et lancez manage.py syncdb si vous devez l’ajouter).

Le squelette de paramètres crée par défaut avec la commande startproject possède déjà deux morceaux d’installés, aussi à moins que vous ne les ayez enlevé, vous n’aurez probablement rien à modifier pour faire fonctionner les sessions.

Si vous ne désirez pas utiliser les sessions, vous devrez enlever la ligne SessionMiddleware de MIDDLEWARE_CLASSES et la ligne 'django.contrib.sessions' de vos INSTALLED_APPS. Ceci ne vous épargnera qu’un peu de surcharge, mais chaque petit morceau compte.

Utiliser les sessions dans les vues

Lorsque SessionMiddleware est activé, chaque objet HttpRequest - le premier argument de chaque fonction vue de Django - aura un attribut de session, qui est un objet assimilable à un dictionnaire. Vous pouvez le lire et écrire dedans de la même manière qu’avec un dictionnaire normal. Par exemple, dans une vue vous pouvez faire des choses comme cela:

# Set a session value:
request.session["fav_color"] = "blue"

# Get a session value -- this could be called in a different view,
# or many requests later (or both):
fav_color = request.session["fav_color"]

# Clear an item from the session:
del request.session["fav_color"]

# Check if the session has a given key:
if "fav_color" in request.session:
    ...

Vous pouvez aussi utiliser d’autre méthode de mapping telles que keys() et items() sur request.session.

Il y a quelques règles simples pour utiliser les sessions Django efficacement:

  • Utiliser des chaînes Python tels que les clefs de dictionnaire sur request.session (par opposition aux entiers, objets, etc.). Ceci est plus une convention qu’une règle intangible, mais il est préférable de la suivre.
  • les clefs du dictionnaire de session commencant par un soulignement sont réservé pour l’usage interne de Django. En pratique, le framework n’utilise seulement qu’un petit nombre de variables de sessions préfixées par un soulignement, mais à moins de toutes les connaîtres (et de vous abliger à coller à tout changement apporté à Django lui-même), rester éloigné de tels préfixes vous évitera que Django interfère avec votre application.
  • Ne remplacez pas request.session par un nouvel objet, et n’accédez pas ou ne déclarez pas ses attributs. Utilisez le comme un dictionnaire Python.

Regardons à présent quelques exemples. Cette vue simpliste fixe une variable has_commented à True après qu’un utilisateur ait posté un commentaire. C’est une manière simple (mais pas particulièrement sûre) d’éviter qu’un utilisateur poste plus d’un commentaire:

def post_comment(request, new_comment):
    if request.session.get('has_commented', False):
        return HttpResponse("You've already commented.")
    c = comments.Comment(comment=new_comment)
    c.save()
    request.session['has_commented'] = True
    return HttpResponse('Thanks for your comment!')

Cette vue simpliste connecte un «membre» du site:

def login(request):
   try:
       m =
       Member.objects.get(username__exact=request.POST['username'])
       if m.password == request.POST['password']:
           request.session['member_id'] = m.id
           return HttpResponse("You're logged in.")
   except Member.DoesNotExist:
       return HttpResponse("Your username and password
       didn't match.")

et celle-ci déconnecte un membre, en accord avec login():

def logout(request):
    try:
        del request.session['member_id']
    except KeyError:
        pass
    return HttpResponse("You're logged out.")

Note

En pratique, c’est une façon moche de connecter des utilisateurs. Dans le framework d’identification abordé rapidement gère cette tâche pour vous de manière plus robuste et utile. Ces exemples sont délibérément simplistes de façon à ce que vous puissiez facilement voir de ce qu’il se passe.

Setting Test Cookies

Comme nous venons de le dire, vous ne pouvez par compter sur le navigateur pour accepter les cookies. Aussi, par commodité, Django fourni un moyen simple de tester si le navigateur de l’utilisateur accepte les cookies. Vous devez simplement appeler request.session.set_test_cookie() dans une vue, puis vérifier request.session.test_cookie_worked() dans une vue postérieure - pas dans le même appel de vue.

Cette coupure maladroite entre set_test_cookie() et test_cookie_worked() est rendue nécessaire par la façon dont fonctionne les cookies. Lorsque vous fixez un cookie, vous ne pouvez en fait dire si le navigateur l’a accepté avant de recevoir la prochaine requêtei de ce navigateur.

C’est une bonne pratique d’utiliser delete_test_cookie() pour nettoyer derrière vous. Faîtes cela après avoir vérifié que le cookie de test a fonctionné.

Voici un exemple typique d’utilisation:

def login(request):

    # If we submitted the form...
    if request.method == 'POST':

        # Check that the test cookie worked (we set it
        below):
        if request.session.test_cookie_worked():

            # The test cookie worked, so delete it.
            request.session.delete_test_cookie()

            # In practice, we'd need some logic to check
            username/password
            # here, but since this is an example...
            return HttpResponse("You're logged in.")

        # The test cookie failed, so display an error
        message. If this
        # was a real site we'd want to display a friendlier
        message.
        else:
            return HttpResponse("Please enable cookies
            and try again.")

    # If we didn't post, send the test cookie along with the
    login form.
    request.session.set_test_cookie()
    return render_to_response('foo/login_form.html')

Note

Encore une fois, les fonctions primitives d’identification gèrent cette vérification pour vous.

Utiliser les sessions en dehors des vues

En interne, chaque session est est simplement un modèle Django normal, défini dans django.contrib.sessions.models. Chaque session est identifiée par un hachage long de plus ou moin 32 caractères aléatoires stocké dans un cookie. Puisque c’est un modèle normal, vous pouvez accéder aux sessions en utilisant l’PI de base de données Django:

>>> from django.contrib.sessions.models import Session
>>> s = Session.objects.get(pk='2b1189a188b44ad18c35e113ac6ceead')
>>> s.expire_date
datetime.datetime(2005, 8, 20, 13, 35, 12)

Vous devrez appeler get_decoded() pour obtenir les données de sessions actuelles. Cela est nécessaire parceque le dictionnaire est stocké dans un format encodé:

>>> s.session_data
'KGRwMQpTJ19hdXRoX3VzZXJfaWQnCnAyCkkxCnMuMTExY2ZjODI2Yj...'
>>> s.get_decoded()
{'user_id': 42}

Quand les sessions sont-elles sauvegardées

Par défaut, Django enregistre uniquement en base de données si la session a été modifié - autrement dit, si aucune des valeurs du dictionnaire n’a été assignée ou éffacée:

# Session is modified.
request.session['foo'] = 'bar'

# Session is modified.
del request.session['foo']

# Session is modified.
request.session['foo'] = {}

# Gotcha: Session is NOT modified, because this alters
# request.session['foo'] instead of request.session.
request.session['foo']['bar'] = 'baz'

Pour changer ce comportement par défaut, placez SESSION_SAVE_EVERY_REQUEST à True. Si SESSION_SAVE_EVERY_REQUEST vaut True, Django enregistrera la session dans la base de données sur chaque requête unique, même s’il n’y a pas eu de changement.

Notez que le cookie de session est envoyé uniquement lorsque une session à été crée ou modifiée. Si SESSION_SAVE_EVERY_REQUEST vaut True, le cookie de session sera envoyé à chaque requête. De façon similaire, la partie expires d’un cookie de session est mise à jour à chaque fois que le cookie de session est envoyé.

Sessions temporaire vs. sessions persistantes

Vous avez peut-être remarqué que le cookie qu’a envoyé Google contient expires=Sun, 17-Jan-2038 19:14:07 GMT;. Les cookies peuvent optionellement contenir une date d’expiration qui renseigne le navigateur sur la date de suppression du cookie. Si un cookie ne contient pas de valeur d’expiration, le navigateur le supprimera lorsque l’utilisateur/trice fermera la fenêtre de celui-ci. Vous pouvez controler le comportement du framework de session concernant ceci grâce au paramètre SESSION_EXPIRE_AT_BROWSER_CLOSE.

Par défaut, SESSION_EXPIRE_AT_BROWSER_CLOSE est placé à False, ce qui signifie que les cookies de sessions seront stockés dans les navigateurs des utilisateurs durant SESSION_COOKIE_AGE seconde(s) (qui est de deux semaines par défaut ou 1,209,600 secondes). Utilisez ceci si vous ne voulez pas que les personnes aient à se connecter à chaque fois qu’elles ouvrent un navigateur.

Si SESSION_EXPIRE_AT_BROWSER_CLOSE est placée à True, Django utilisera un cookie temporaire.

Autres paramètres de session

En dehors des paramètres déjà mentionnés, d’autres paramètres influencent la manière dont le framework de sessions Django utilise les cookies, comme le montre le tableau 12-2.

Tableau 12-2. Paramètres influant sur le comportement d’un cookie

Setting Description Default
SESSION_COOKIE_DOMAIN Le domaine à utiliser pour les cookies de session. déclarez une chaîne telle que ".lawrence.com" pour les cookies multi-domaines, ou utilisez None pour un cookie standard. None
SESSION_COOKIE_NAME le nom du cookie à utiliser pour les sessions. Cela peut-être n’importe quelle chaîne. "sessionid"
SESSION_COOKIE_SECURE S’il faut utiliser un cookie «sécurisé» pour le cookie de session. S’il vaut True, le cookie sera marqué comme étant «sécurisé», ce qui signifie que le navigateur s’assurera que le cookie transite uniquement par HTTPS. False

Technical Details

Pour les curieux, voici quelques notes techniques au sujet du fonctionnement interne du framework de session:

  • le dictionnaire de session accepte n’importe quel objet Python capable d’être «picklé». Lisez la documentation au sujet du module pickle embarqué par Python pour des indications sur son fonctionnement.

  • les données de session sont stockées dans une table de la base de données appelée django_session.

  • les données de session sont récupéré à la demande. Si vous n’accédez jamais à request.session, Django n’interrogera pas la table de la base de données.

  • Django envoie un cookie uniquement s’il y a besoin. Si vous ne déclarez aucune données de session, il n’envera pas de cookie de session (à moins que SESSION_SAVE_EVERY_REQUEST soit fixée à True).

  • Le framework de session sous Django est entièrement, et uniquement, basé sur les cookies. Il ne finit pas par placer des IDs de session dans les URLs en dernioer recourt, comme peuvent le faire d’autres outils (PHP, JSP).

    C’est une décision d’implémentation intentionnelle. Placer les sessions dans les URLs n’abouti pas seulement à faire des URLs laids, mais rends aussi votre site vulnérable à une certaine forme de vol d’ID de session, via l’en-tête Referer.

Si vous êtes toujours curieux, les sources sont assez explicites; consultez django.contrib.sessions pour plus de détails.

Utilisateurs et identification

Nous sommes à présent à mi-chemin de lier des navigateurs directement à des Personnes Réelles™. Les sessions nous donne un moyen de rendre les données persistantes lors des requêtes multiples du navigateur; la deuxième partie de l’équation est d’utiliser ces sessions pour l’identifiaction de l’utilisateur. Bien sure, nous ne pouvons pas simplement croire que les utilisateurs sont bien ceux qu’il prétendent être, nous devons donc les identifier en chemin.

Naturellement, Django fournit des outils pour gérer cette tâche courante (et bien d’autres). Le système d’identification des utilisateurs sous Django gère les comptes utilisateurs, les groupes, les permissions et les sessions utilisateur basées sur les cookies. Ce système est souvent appelé système auth/auth («authentication» et «authorization», identification et autorisation). Ce nom reconnait qu’avoir affaire à des utilisateurs est souvent un processus à deux étapes. Nous devons

  1. Vérifier (authenticate) que l’utilisateur/trice est bien celui ou celle qu’il/elle prétend être(habituellement en vérifiant un nom et n mot de passe dans une base de données des utilisateurs)
  2. Vérifier que l’utilisateur est authorized à faire les opérations indiquées (habituellement en vérifiant la table des permissions).

En suivant ces besoins, le système auth/auth de Django se constitue de plusieurs parties:

  • Users: les personnes enregistrées sur votre site.
  • Permissions: de drapeaux binaires (oui/non) désignant si un utilisateur peut effectuer une certaine tâche
  • Groups: une façon générique d’appliquer des étiquettes et des permissions à plus d’un utilisateur.
  • Messages: une façon simple d’empiler et d’afficher les messages du système aux utilisateurs
  • Profiles: un mécanisme pourt étendre l’objet utilisateur avec des champs personnalisés.

Si vous avez utilisez l’outil d’administration (détaillé au chapitre 6), vous avez déjà vu beaucoup de ces outils, et si vous avez éditez des utilisateurs ou des groupes, vous avez en fait édité des données dans les tables de la base de données du système d’autentification.

Activer le support d’autentification

Tout comme les outils de session, le support d’identification est livré sous forme d’application Django dans django.contrib, qui doit être installé. Comme le système de session, il est installé par défaut, mais si vous l’avez supprimé, vous devrez suivre ces étapes pour lm’installer:

  1. Assurez-vous que le framework de session soit installé tel que décrit plus tôt dans ce chapitre. Conserver les traces des utilisateurs requiert évidemment des cookies, et ceux-ci sont construits par le framework de session.
  2. Placez 'django.contrib.auth' dans votre paramètre INSTALLED_APPS puis lancez manage.py syncdb.
  3. Assurez-vous que 'django.contrib.auth.middleware.AuthenticationMiddleware' soit dans votre paramètre MIDDLEWARE_CLASSES après SessionMiddleware.

Avec cette installation, nous sommes prêts à manipuler des utilisateurs dans les fonctions vues. L’interface principale que vous utiliserez pour accéder aux utilisateurs au sein d’une vue est request.user; c’est un objet qui représente l’utilisateur actuellement connecté. Si l’utilisateur n’est pas connecté, il sera considéré comme un objet ANonymousUser (voir plus loin pour les détails).

Vous pouvez facilement dire si un utilisateur est connecté avec la méthode is_authenticated():

if request.user.is_authenticated():
    # Do something for authenticated users.
else:
    # Do something for anonymous users.

Utiliser les utilisateurs

Une fois que vous avez un User - souvent depuis request.user, mais aussi potentiellement grâce à l’une des autres méthodes rapidement abordées - vous avez des nombreux champs et méthodes disponiblent sur cet objet. Les objets AnonymousUser émulent une partie de cette interface, mais pas complétement, vous devez donc contrôler user.is_authenticated() avant de considérer que vous avez affaire à un objet utilisateur de bonne foi. Les tableaux 12-3 et 12-4 listent les champs et les méthodes sur les objets User, respectivement.

Tableau 12-3. Champs des objets User

Champ Description
username Requis; 30 caractères ou moin. Caractères alphanumériques uniquement (lettres, chiffres, et
first_name Optionel; 30 caractères ou moin.
last_name Optionel; 30 caractères or moin.
email Optionnel. Adresse de courièl
password Requis. Un hachage et des méta-données sur le mot de passe (Django ne stocke pas les mots de passe bruts). Lisez la partie «Mot de passe» pour en savoir plus au sujet de cette valeur.
is_staff Booléen. Désigne si l’utilisateur a accès au site d’administration.
is_active Booléen. Désigne si ce compte peut être utilisé pour se connecter. Placez ce drapeau à False au lieu de supprimer les comptes.
is_superuser Booléen. désigne si cet utilisateur possède toutes les permissions sans explicitement les lui assigner.
last_login Un marqueur de la dernière connection de l’utilisateur. Il prend la valeur de la date/heure courante par défaut.
date_joined Un marqueur désignant la date de création du compte. Il prend la valeur de la date/heure courante lors de la création du compte.

Tableau 12-4. Méthodes des objets User

Méthode Description
is_authenticated() Renvoie toujours True pour les objets User «réels». C’est une manière de savoir si l’utilisateur à été idnetifié. Ceci n’implique aucunes permissions, et ne contrôle pas si l’utilisateur est actif. Ceci indique seulement que l’utilisateur à été identifié avec succès.
is_anonymous() Renvoie True seulement pour mes objets AnonymousUser (et False pour les objets User «réels». Généralement, vous préférerez utiliser is_authenticated() plutôt que cette méthode.
get_full_name() Renvoie le first_name plus le last_name, avec une espace entre les deux.
set_password(passwd) Parmaètre le mot de passe utilisateur selon la chaîne brute indiquée, en prenant soin de hacher le mot de passe. Ceci ne sauvegarde pas l’objet User.
check_password(passwd) Renvoie True si la chaîne brute indiquée correspond au mot de passe de l’utilisateur. Elle prends en charge le hachage dumot de passe lors de la comparaison.
get_group_permissions() Renvoie une liste des chaînes de permissions que l’utilisateur possède au travers des groupes auquels il appartient.
get_all_permissions() Renvoie une liste de permission que l’utilisateur possède, à la fois via les goupes et les permissions utilisateur.
has_perm(perm) Renvoie True si l’utilisateur possède les permissions spécifiées, où perm est au format "package.codename". Si l’utilisateur est inactif, cette méthode retournera toujours False.
has_perms(perm_list) Renvoie True si l’utilisateur possède toutes les permissions spécifiées. Si l’utilisateur est inactif, cette méthode renverra toujours False.
has_module_perms(app_label) Renvoie True si l’utilisateur à l’une des permissions dans app_label précisé. Si l’utilisateur est inactif, cette méthode renverra toujours False.
get_and_delete_messages() Renvoie une liste d’objets Message dans la file d’attente des utilisateurs et efface les message de la file.
email_user(subj, msg) Envoie un courrier à l’utilisateur. Ce courrier est envoyé depuis le paramètre DEFAULT_FROM_EMAIL. Vous pouvez aussi transmettre un troisième argument, from_email, pour écraser le From du courrier.
get_profile() Renvoie un profile spécifique au site pour cet utilisateur. Consulter la section «Profiles» pour en savoir plus sur cette méthode.

Finalement, les objets User ont deux champs plusieur-à-plusieur: groups et permissions. Les objets User peuvent accéder à leurs objets liés de la même façon que tout autre champ plusieur-à-plusieur:

# Set a user's groups:
myuser.groups = group_list

# Add a user to some groups:
myuser.groups.add(group1, group2,...)

# Remove a user from some groups:
myuser.groups.remove(group1, group2,...)

# Remove a user from all groups:
myuser.groups.clear()

# Permissions work the same way
myuser.permissions = permission_list
myuser.permissions.add(permission1, permission2, ...)
myuser.permissions.remove(permission1, permission2, ...)
myuser.permissions.clear()

Connexion et déconnexion

Django fourni des vues pour gérer la connexion et la déconnexion (et autres astuces géniales), mais avant d’en arriver là, étudions la manière de connecter et déconnecter des utilisateurs «à la main». Django fournit deux fonctions dans django.contrib.auth pour faire ces actions: authenticate() et login().

Pour identifier les noms et mot de passe d’un utilisateur donné, utilisez authenticate(). Elle accepte deux arguments mot-clef, username et password, et retourne un objet User si le mot de passe est valide pour le nom d’utilisateur donné. Si le mot de passe est invalide, authenticate() renvoie None:

>>> from django.contrib import auth
>>> user = auth.authenticate(username='john', password='secret')
>>> if user is not None:
...     print "Correct!"
... else:
...     print "Oops, that's wrong!"

authenticate() vérifie uniquement les références de l’utilisateur. Pour connecter un utilisateur, utilisez login(). Elle prends un objet HttpRequest et un objet User puis enregistre l’ID de l’utilisateur dans la session, en utilisant le framework de session Django.

Cet exemple vous montre comment vous pouvez urtiliser à la fois authenticate() et login() à l’intérieur d’une vue:

from django.contrib import auth

def login(request):
    username = request.POST['username']
    password = request.POST['password']
    user = auth.authenticate(username=username,
    password=password)
    if user is not None and user.is_active:
        # Correct password, and the user is marked "active"
        auth.login(request, user)
        # Redirect to a success page.
        return HttpResponseRedirect("/account/loggedin/")
    else:
        # Show an error page
        return HttpResponseRedirect("/account/invalid/")

Pour déconnecter un utilisateur, utilisez django.contrib.auth.logout() dans votre vue. Elle prends un objet HttpRequest et n’a pas de valuer de retour:

from django.contrib import auth

def logout(request):
    auth.logout(request)
    # Redirect to a success page.
    return HttpResponseRedirect("/account/loggedout/")

Notez que logout() ne lève aucune erreurs si l’utilisateur n’est pas connecté.

En pratique, vous n’aurez habituellement pas besoin d’écrire vos propres fonctions de «login/logout»; le système d’identification est livré avec un jeu de vues génériques pour prendre en charge la connexion et la déconnexion.

La première étape dans l’utilisation des vues d’identification est de les ajouter à votre URLconf. Vous devrez ajouter cet extrait :

from django.contrib.auth.views import login, logout

urlpatterns = patterns('',
    # existing patterns here...
    (r'^accounts/login/$',  login),
    (r'^accounts/logout/$', logout),
)

/accounts/login/ et /accounts/logout/ sont les URLs par défaut que Django utilise pour ces vues.

Par défaut, la vue login renvoie génère un gabarit à l’adresse registration/login.html (vous pouvez changer le nom de ce gabarit en passant un argument à la vue, template_name). Ce formulaire doit contenir un champ username et un champ password. Un simple gabarit doit resssembler à ceci:

{% extends "base.html" %}

{% block content %}

  {% if form.errors %}
    <p class="error">Sorry, that's not a valid username or
    password</p>
  {% endif %}

  <form action='.' method='post'>
    <label for="username">User name:</label>
    <input type="text" name="username" value="" id="username">
    <label for="password">Password:</label>
    <input type="password" name="password" value=""
    id="password">

    <input type="submit" value="login" />
    <input type="hidden" name="next" value="{{ next|escape }}" />
  </form>

{% endblock %}

Si l’utilisateur/trice se connecte avec succès, il ou elle sera redirigée vers /accounts/profile/ par défaut. Vous pouvez outrepasser cela en ajoutant un champ caché appelé next avec l’URL de redirection une fois la connection établie. Vous pouvez aussi transmettre cette valeur sous forme de paramètre GET à la vue de connexion et elle sera automatiquement ajoutée au contexte en tant que varaible nommée next que vous pouvez insérer dans ce champ caché.

La vue de déconnexion fonctionne un peu différement. Par défaut elle génère un gabarit à l’adresse registration/logged_out.html (qui contient habituellement un message «Vous êtes bien déconnecté»). Cependant, vuos pouvez appeler la vue avec un argument supplémentaire, next_page, qui informera la vue de faire une redirection après une déconnexion.

Limiter l’accès des utilisateurs connectés

Bien sûr, la raison pour laquelle nous sommes tous passez par ces ennuis est que nous voulons limiter l’accès à certaines parties du site.

La façon simple, brute, de limiter l’acces à certaines pages est de controler request.user.is_authenticated() puis de rediriger vers une page de login:

from django.http import HttpResponseRedirect

def my_view(request):
    if not request.user.is_authenticated():
        return HttpResponseRedirect('/login/?next=%s' %
        request.path)
    # ...

ou bien afficher un message d’erreur:

def my_view(request):
    if not request.user.is_authenticated():
        return render_to_response('myapp/login_error.html')
    # ...

Pour allez plus vite, vous pouvez utiliser le bien pratique décorateur, login_required:

from django.contrib.auth.decorators import login_required

@login_required
def my_view(request):
    # ...

login_required procède de la sorte:

  • si l’utilisateur n’est pas connecté, elle redirige vers /accounts/login/, passant l’URL absolut courant dans la chaîne de requête sous forme de next, par exemple: /accounts/login/?next=/polls/3/.
  • si l’utilisateur est connecté, exécute la vue normalement. Le code de la vue peut ensuite considérer que l’utilisateur est connecté.

Limiter l’acces aux utilisateurs passant un test

Limiter l’accès basé sur selon certaines permissions ou sur un autre test, et fournir un emplacement différent pour la vue de connexion, tout ceci fonctionne essentiellement de la même manière.

La méthode brute consiste à lancer votre test sur le request.user directement dans la vue. Par exemple, cette vue s’assure que l’utilisateur est connecté et qu’il possède l’autorisation polls.can_vote (des détails sur le fonctionnement des autorisations suivent):

def vote(request):
    if request.user.is_authenticated() and
    request.user.has_perm('polls.can_vote')):
        # vote here
    else:
        return HttpResponse("You can't vote in this poll.")

Encore une fois, Django fourni un raccourcis appelé user_passes_test. Il accepte des arguments et génère un décorateur spécialisé selon votre situation particulière:

def user_can_vote(user):
    return user.is_authenticated() and
    user.has_perm("polls.can_vote")

@user_passes_text(user_can_vote, login_url="/login/")
def vote(request):
    # Code here can assume a logged-in user with the correct
    permission.
    ...

user_passes_test impose un argument: un «callable» qui prends un objet User et renvoie True si l’utilisateur est autorisé à voir la page. Notez que user_passes_test ne vérifie pas automatiquement que le User est identifé; vous devez faire cela par vous même.

Dans cet exemple nous montrons aussi le deuxième argument optionnel, login_url, qui vous permet de préciser l’URL de votre page de connection (/accounts/login/ par défaut).

Puisque vérifier si un utilisateur possède une autorisation particulière est une tâche relativement courant, Django fourni un raccourcis pour ce cas précis: le décorateur permission_required(). En utilisant ce décorateur, l’exemple précédent peut-être écrit comme suit:

from django.contrib.auth.decorators import permission_required

@permission_required('polls.can_vote', login_url="/login/")
def vote(request):
    # ...

Notez que permission_required() accepte aussi un paramètre optionnel login_url, qui est aussi '/accounts/login/' par défaut.

Limiter l’accès aux vues génériques

Une dès question les plus fréquemment posée sur la liste des utilisateurs de Django concerne la limitation d’accès à une vue générique. Pour réussir cela, vous devrez écrire un petit emballage autour de la vue et pointer votre URLconf vers celui-ci plutôt que vers la vue générique elle-même:

from dango.contrib.auth.decorators import login_required
from django.views.generic.date_based import object_detail

@login_required
def limited_object_detail(*args, **kwargs):
    return object_detail(*args, **kwargs)

Vous pouvez, bien sûr, remplacer login_required par tout autre décorateur limitant.

Gérer les utilisateurs, les autorisations, et les groupes

La façon de loin la plus simple pour gérer le système d’autentification est d’utiliser l’interface d’administration. Le chapitre 6 aborde la façon d’utiliser l’interface d’administration de Django pour éditer les utilisateurs et contrôler leurs permissions et leurs accès. La plupart du temps vous utiliserez uniquement cette interface.

Cependant, il existe un API de bas niveau que vous pouvez explorer lorsque vous avez besoin d’un contrôle absolu, et nous discuterons de cela dans les sections qui suivent.

Créer des utilisateurs

Créer des utilisateurs avec la fonction assistante, create_user:

>>> from django.contrib.auth.models import User
>>> user = User.objects.create_user(username='john',
...                                 email='jlennon@beatles.com',
...                                 password='glass onion')

À cet instant, user est une instance User prète à être enregistrée dans la base de données (en fait, create_user() n’appelle pas save() en elle-même). Vous pouvez aussi continuer à modifier ces attributs avant la sauvegarde:

>>> user.is_staff = True
>>> user.save()
Modifier les mots de passe

Vous pouvez changer le mot de passe avec set_password():

>>> user = User.objects.get(username='john')
>>> user.set_password('goo goo goo joob')
>>> user.save()

Ne fixez pas l’attribut password directement à moins que vous ne sachiez ce que vous faites. Le mot de passe est en fait stocké sous forme de salted hash et ne peut donc être édité directement.

Plus formellement, l’attribut password d’un objet User est une chaîne dans ce format:

hashtype$salt$hash

Il s’agit d’un type de hachage, du «salt», et du hachage lui-même, séparé par le caractère dollar ($).

hashtype est soit un sha1 (par défaut) ou un md5, l’algorithme utilisé pour procéder à un hachage à sens unique du mot de passe. salt est une chaîne aléatoire utilisée pour «assaisonner» le mot de passe brute avant la création du hachage, par exemple:

sha1$a1976$a36cc8cbf81742a8fb52e221aaeab48ed7f58ab4

Les fonctions User.set_password() et User.check_password() gèrent le paramètre et vérifient ces valeurs en coulisses.

Est-ce que le «Salted Hash» est un genre de drogue ?

Non, un salted hash n’a rien à voir avec la marijuana; c’est en fait une façon courante de stocker les mot de passe de façon sécurisée. Un hash (hachage) est une fonction cryptographique à sens unique - autrement dit, vous pouvez facilement calculer le hachage d’une valeur donnée, mais il est presque impossible de prendre un hachage et de reconstruire la valeur originale.

Si nous stockons les mots de passe sous forme de texte, tous ceux qui ont accès à la base de données des mots de passe connaitrons instantanément les mots de passe de tout le monde. Stocker les mots de passe sous forme de hachage réduit la valeur d’une base de données compromise.

Cependant, un attaquant avec le mot de passe de la base de données peut toujours lancer une attaque par force brute, hachant des millions de mots de passe et les comparant avec les hachages stockés. Cela prends certe du temps, mais moins que vous ne pourriez le penser - les ordinateurs sont incroyablement rapides.

Pire, il existe des tables rainbow (arc-en-ciel) disponibles publiquement, ou des bases de données proposant des hachages pré-calculés de millions de mots de passe. Avec une table arc-en-ciel, un attaquant peut casser la plupart des mots de passe en quelques secondes.

Ajouter un salt - une simple valeur aléatoire initiale - au hachage stocké ajoute une autre couche de difficulté pour casser les mots de passe. Puisque les salts diffèrent entre les mots de passe, il préviennent aussi de l’utilisation des table arc-en-ciel, car ceci oblige les attaquants à se replier sur une attaque par force brute, elle même rendu plus difficile par l’entropie ajoutée au hachage par le salt.

Même si les hachages «salted» ne sont pas la façon la plus sûre de stocker des mots de passe dans l’absolu, ils sont un bon compromis entre la sécurité et l’aspect pratique.

Gérer les comptes

Nous pouvons utiliser ces outils bas niveau pour créer des vues qui permettent au utilisateur de s’enregistrer. Presque tous les développeurs veulent implémenter la souscription de manière différente, Django vous laisse donc écrire une vue pour les inscriptions selon vos besoins. Heureusement, c’est assez facile.

Pour faire au plus simple, nous pouvons fournir une petite vue qui demande à l’utilisateur des informations puis crée ensuite ces utilisateurs. Django fournit un formulaire que vous pouvez utiliser pour ce faire, et que nous utiliserons dans cet exemple:

from django import oldforms as forms
from django.http import HttpResponseRedirect
from django.shortcuts import render_to_response
from django.contrib.auth.forms import UserCreationForm

def register(request):
    form = UserCreationForm()

    if request.method == 'POST':
        data = request.POST.copy()
        errors = form.get_validation_errors(data)
        if not errors:
            new_user = form.save(data)
            return HttpResponseRedirect("/books/")
    else:
        data, errors = {}, {}

    return render_to_response("registration/register.html", {
        'form' : forms.FormWrapper(form, data, errors)
    })

Ce formulaire considère qu’un gabarit appelé registration/register.html existe. Voici un exemple de ce à quoi peut ressembler un gabarit:

{% extends "base.html" %}

{% block title %}Create an account{% endblock %}

{% block content %}
  <h1>Create an account</h1>
  <form action="." method="post">
    {% if form.error_dict %}
      <p class="error">Please correct the errors below.</p>
    {% endif %}

    {% if form.username.errors %}
      {{ form.username.html_error_list }}
    {% endif %}
    <label for="id_username">Username:</label> {{ form.username
    }}

    {% if form.password1.errors %}
      {{ form.password1.html_error_list }}
    {% endif %}
    <label for="id_password1">Password: {{ form.password1 }}

    {% if form.password2.errors %}
      {{ form.password2.html_error_list }}
    {% endif %}
    <label for="id_password2">Password (again): {{ form.password2
    }}

    <input type="submit" value="Create the account" />
  </label>
{% endblock %}

Note

django.contrib.auth.forms.UserCreationForm est, au moment de la mise sous presse, une ancienne version de formulaire. Lisez http://www.djangoproject.com/documentation/0.96/forms/ pour les détails à propos des anciens formulaires. La transition vers les nouveaux formulaires, telle qu’abordée au chapitre 7, sera complétée dans un futur proche.

Utiliser les données d’identification dans les gabarits

L’utilisateur actuellement connecté ainsi que ses permissions sont rendus disponibles dans le gabarit contextuel lorsque vous utilisez RequestContext (voir le chapitre 10).

Note

Techniquement, ces variables sont disponibles uniquement dans le contexte du gabarit si vous utilisez RequestContext et que votre paramètre TEMPLATE_CONTEXT_PROCESSORS contient "django.core.context_processors.auth", ce qui est ainsi par défaut. Encore une fois, lisez le chapitre 10 pour plus d’informations.

En utilisant RequestContext, l’utilisateur courant (soit une instance de User, soit une instance de AnonymousUser) est stocké dans la variable de gabarit {{ user }}:

{% if user.is_authenticated %}
  <p>Welcome, {{ user.username }}. Thanks for logging in.</p>
{% else %}
  <p>Welcome, new user. Please log in.</p>
{% endif %}

Les permissions de l’utilisateur sont stocké dans la variable de gabarit {{ perms }}. C’est un proxy, ouvert aux gabarits, vers un jeu de méthodes d’autorisations décrites d’ici peu.

Il existe deux façons d’utiliser cet objet perms. Vous pouvez utiliser quelque chose comme {{ perms.polls }} pour vérifier si l’utilisateur possède certaines permissions pour une application données, ou vous pouvez utiliser quelque chose comme {{ perms.polls.can_vote }} pour vérifier si l’utilisateur à des permissions spécifiques.

Ainsi, vous pouvez vérifier les permissions dans les instructions {% if %} de gabarit:

{% if perms.polls %}
  <p>You have permission to do something in the polls app.</p>
  {% if perms.polls.can_vote %}
    <p>You can vote!</p>
  {% endif %}
{% else %}
  <p>You don't have permission to do anything in the polls app.</p>
{% endif %}

Autres composants: Permissions, groupes, messages, et profiles

Il y a quelques parties du framework d’identification que nous n’avons fait qu’aborder en passant. Nous les observerons de plus près dans les sections suivantes:

Permissions

Les permissions sont une manière simple de «marquer» les utilisateurs et les groupes comme étant capable de faire certaines actions. Elles sont généralement utilisées par le site d’administration de Django, mais vous pouvez aisément les utiliser dans votre propre code.

Le site d’administration de Django utilise les permissions suivantes:

  • l’accès à la vue du formulaire d’ajout, ainsi qu’à l’ajout d’objet se limite aux utilisateur sayant la permission add pour ce type d’objet.
  • l’accès à la vue de la liste des modifications, à la vue du formulaire de modification, ainsi qu’à la modification d’un objet est limitée aux utilisateurs ayant la permission change pour ce type d’objet.
  • l’accès à la suppression d’objet est limité aux utilisateurs ayant la permission delete pour ce type d’objet.

Les permissions sont fixé globalement par type d’objet, et non pas par instance spécifique d’objet. Par exemple, il est possible de dire «Mary peut modifier les actualités», mais il n’est pas actuellement possible de dire «Mary peut changer les actualités, mais uniquement celles qu’elle a crée elle-même» ou «Mary peut changer uniquement les actualités qui ont un certains status, une certaine date de publication, ou un certain ID».

Ces trois permissions de base - ajout, modification, suppression - sont automatiquement crées pour chaque modèle Django possédant une class Admin. En coulisses, ces permissions sont ajouté à la base de données auth_permission lorsque vous lancez la commande manage.py syncdb.

Ces permissions seront de la forme "<app>.<action>_<object_name>". Ceci dit, si vous avez une application polls avec un modèle Choice, vous obtiendrez des permissions nommées "polls.add_choice", "polls.change_choice", et "polls.delete_choice".

Notez que si votre modèle n’a pas de class Admin lorsque vous lancez syncdb, les permissions ne seront pas crées. Si vous initialisez votre base de données et ajoutez class Admin aux modèles après cela, vous devrez à nouveau lancer syncdb pour créer toutes lespermissions manquantes pour vos applicationsinstallées.

Vous pouvez aussi créer des permissions personnalisées pour un objet donné, en utilisant l’attribut permissions sur Meta. Cet exemple de modèle crée trois permissions personnalisées:

class USCitizen(models.Model):
   # ...
   class Meta:
       permissions = (
           # Permission identifier     human-readable
           permission name
           ("can_drive",               "Can drive"),
           ("can_vote",                "Can vote in
           elections"),
           ("can_drink",               "Can drink
           alcohol"),
       )

Ce code créer ces permissions supplémentaires uniquement lorsque vous lancez syncdb; il vous revient de vérifier ces permissions dans vos vues.

Tout comme les utilisateurs, les permissions sont implémentées dans un modèle Django se trouvant dans django.contrib.auth.models. Cela signifie que vous pouvez utiliser l’API de base de données de Django pour agir directement sur les permissions si vous le désirez.

Groupes

Les groupes sont une façon générique de catégoriser les utilisateurs de façon à pouvoir appliquer des permissions, ou d’autres étiquettes, à ces utilisateurs. Un utilisateur peut appartenir à plusieurs groupes.

Un utilisateur dans un groupe obtient automatiquement les autorisations accordées à ce groupe. Par exemple, si le groupe Site editors possède l’autorisation can_edit_home_page, tous les utilisateurs de ce groupe auront cette autorisation.

Les groupes sontaussi une façon commode de catégoriser les utilisateurs de façon à leur donner certinaes étiquettes, ou des fonctionnalités étendues. Par exemple, vouspouvez créer un groupe 'Special users', et vous pouvez écrire du code qui, admettons, donne à ces utilisateurs un accès à une partie du site réservée uniquement aux membres, ou envoie des courrièls uniquement aux membres.

Comme pour les utilisateurs, la manière la plus simple de gérer des groupes est d’utiliser l’interface d’administration. Cependant, les groupes sont aussi de simples modèles Django qui résident dans django.contrib.auth.models, ainsi là encore vous pouvez toujours utiliser l’API de base de données de Django pour gérer les groupes au plus bas niveau.

Messages

Le système de message est une façon légère de faire une file d’attente des messages pour des utilisateurs donnés. Un message est associé à un User. Il n’y a pas de concept d’expiration ou d’horodatage.

Les messages sont utilisés par l’interface d’administratino de Django après une série d’actions réussies. Par exemple, lorsque vous créez un objet, vous remarquerez un message «L’objet à été crée avec succès» en haut de la page d’administration.

Vous pouvez utiliser la même API pour faire une file et afficher les messages dans votre propre application. L’API est simple:

  • pour créer un nouveau message, utilisez user.message_set.create(message='message_text').
  • pour récupérer/supprimer des messages, utilisez user.get_and_delete_messages(), qui retourne une liste des objets Message dans la file de l’utilisateur (s’il existe) et supprime les messages de la file.

Dans cet exemple de vue, le système enregistre un message pour l’utilisateur après avoir créé une liste de lecture:

def create_playlist(request, songs):
    # Create the playlist with the given songs.
    # ...
    request.user.message_set.create(
        message="Your playlist was added successfully."
    )
    return render_to_response("playlists/create.html",
        context_instance=RequestContext(request))

Lorsque vous utilisez RequestContext, l’utilisateur actuellement connecté ainsi que son message sont rendu disponibles dans le contexte de gabarit sous la forme de la variable {{ messages }}. Voici un exemple de code d’un gabarit qui affiche les messages:

{% if messages %}
<ul>
    {% for message in messages %}
    <li>{{ message }}</li>
    {% endfor %}
</ul>
{% endif %}

Notez que les appels à RequestContext get_and_delete_messages (récupèrent_et_suppriment_les_messages) en coulisses, ainsi tout message sera effacé même si vous ne les affichez pas.

Finallement, notez que ce framework de message fonctionne uniquement avec les utilisateurs existant dans la base de données des utilisateurs. Pour envoyer un message à un utilisateru anonyme, utilisez directement le framework de session.

Profiles

La pièce finale du puzzle est le système de profile. Pour comprendre ce que sont les profiles , jetons un oeil au problème.

En résumé, beaucoup de site ont besoin de stocker plus d’information sur l’utilisateur que celle disponible dans l’objet User standard. Pour limiter le problème, la plupart des sites auront des champs «supplémentaires». Ainsi, Django fourni une manière légère de définir un objet «profile» qui est lié à un utilisateur donné. Cet objet profile peut différer de projet en projet, et peut même gérer différents profiles pour différents sites servis depuis la même base de données.

la première étape dans la création d’un profile est de définir un modèle qui porte les informations de profil. Le seul pré requis qu’impose Django est de définir un modèle qui possède une unique ForeignKey vers le modèle User; ce champ doit s’appeler user. Mis à part cela, vous pouvez utiliser autant de champs que vous le désirez. Voici un modèle de profile totalement arbitraire:

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

class MySiteProfile(models.Model):
    # This is the only required field
    user = models.ForeignKey(User, unique=True)

    # The rest is completely up to you...
    favorite_band = models.CharField(maxlength=100, blank=True)
    favorite_cheese = models.CharField(maxlength=100, blank=True)
    lucky_number = models.IntegerField()

Ensuite, vous devrez indiquer à Django où il doit chercher cet objet profil. Vous faites cela en paramètrant AUTH_PROFILE_MODULE selon l’identifiant de votre modèle. Donc, si votre modèle réside dans une application appelée myapp, vous placerez ceci dans votre fichier de paramètres:

AUTH_PROFILE_MODULE = "myapp.mysiteprofile"

Une fois ceci fait, vous pouvez accéder à un profil utilisateur en appelant user.get_profile(). Cette fonction peut lever une exception SiteProfileNotAvailable si AUTH_PROFILE_MODULE n’est pas défini, ou elle peut lever une exception DoesNotExist si l’utilisateur ne possède pas de profil (généralement, vous récupérerez cette exception pour créer un nouveau profile à ce moment là).

Et ensuite ?

Oui, le sytème de session et d’autorisation est un gros morceau à avaler. La plupart du temps, vous n’aurez pas besoin de toutes les fonctionnalités décrites dans ce chapitre, mais lorsque vous avez besoin d’interactions complexes entre les utilisateurs, il est bon d’avoir toute cette puissance disponible.

Dans le chapitre suivant, nous nous pencherons sur une partie de Django construite au dessus de ce système de session/utilisateur: l’application de commentaires. Elle vous permet d’attacher facilement des commentaires - des utilisateurs anonymes ou identifiés - à des objets arbitraires. En avant et toujours plus haut !

<< précédentsuivant >>

Dernière modification: 2010-05-04 10:26:26.481374