2012-08-29 5 views
3

Nous exécutons plusieurs sites django (appelons-les site1, site2, site3) par rapport à la même base de données, et nous souhaitons autoriser les noms d'utilisateurs en double. Le site et le cadre d'authentification ne semblent pas réaliser cela, par défaut, le nom d'utilisateur est un champ unique dans auth.User.Plusieurs sites et utilisateurs

Donc ce que je l'ai fait jusqu'à présent (patch singe, déconner avec l'objet utilisateur ...):

User._meta.get_field('username')._unique = False 
User.add_to_class('site', models.ForeignKey(Site, default=Site.objects.get_current().id, blank=True, null=True)) 
User._meta.unique_together = (('username', 'site'),) 

Cette pièce supprime l'unicité du nom d'utilisateur, ajouter un champ de site, faire le couple (nom d'utilisateur, site) unique.

Puis viennent les problèmes qui pourraient survenir lors de la demande d'un User.objects.get (username = xx) (par exemple, backends d'authentification), si certains utilisateurs ont le même nom d'utilisateur sur un site différent. Donc, j'ai décidé de patcher le gestionnaire User.objects:

def get_query_set(filter=True): 
    q = QuerySet(User.objects.model, using=User.objects._db) 
    if filter: 
     return q.filter(site = Site.objects.get_current()) 
    return q 
User.objects.get_query_set = get_query_set 

semble fonctionner jusqu'à présent. Mais ... les sites utilisent à peu près les mêmes objets, et il est probable que nous changions le champ utilisateur de ces objets en utilisant l'interface d'administration, qui est commune à tous les sites ... donc, si je veux attribuer un objet (qui a une clé étrangère à auh.User) à un utilisateur de site2 tout en étant connecté en tant qu'administrateur sur site1, cela ne fonctionnera pas, car le gestionnaire d'utilisateurs filtrera sur site = site1.

Je creusa un peu, a constaté que cela semble fonctionner:

class UserDefaultManager(UserManager): 
    def get_query_set(self, filter=None): 
     return QuerySet(User.objects.model) 
User._default_manager = UserDefaultManager() 

Pour autant que je comprends, _default_manager est utilisé par le gestionnaire des objets connexes. Ensuite, le filtre User.objects.get (username = xx) sur les sites, et an_object.user ne le fera pas. Eh bien, la question est: oui, c'est désordonné, et je suis sûr qu'il y aura des défauts, mais lesquels sont-ils?

La question suivante est: si elle est valide, alors quel est le meilleur endroit pour mettre cette partie du code? Il est actuellement dans un fichier models.py, juste couru que le module est chargé ...

+0

Ne serait-il pas plus simple de stocker les sites pour lesquels un nom d'utilisateur est valide et de vérifier cette liste lors de l'authentification? De cette façon, vous pouvez offrir à un utilisateur commençant sur un site différent qui utilise déjà la possibilité de réutiliser son identifiant, comme le fait Stack Exchange. –

+0

D'autres méthodes seraient plus simples et moins __messy__ mais si vous voulez vraiment utiliser celui-ci, alors vous devriez créer un fichier __manager.py__ – BlueMagma

+0

Cette question vous donne-t-elle des idées? http://stackoverflow.com/questions/4662348/implementing-single-sign-on-sso-using-django – Pramod

Répondre

2

Au lieu de cela, je vous propose d'utiliser un profil:

models.py:

from django.contrib.auth.models import User 


class UserProfile(models.Model): 
    """ Modèle ajoutant des propriété au modèle User """ 
    user = models.OneToOneField(User, editable=False) 
    site1 = models.BooleanField() 
    site2 = models.BooleanField() 
    site3 = models.BooleanField() 


def create_user_profile(sender, instance, created, **kwargs): 
    """ Crée la jonction entre le modèle User, et le modèle UserProfile """ 
    if created: 
     UserProfile.objects.create(user=instance) 

post_save.connect(create_user_profile, sender=User) 

et chaque site que vous créez un décorateur:

decorators.py:

try: 
    from functools import wraps 
except ImportError: 
    from django.utils.functional import wraps 
from django.http import HttpResponseForbidden 
from django.contrib.auth.decorators import login_required 
from distrib.views.error import error403 


def site1_required(function): 
    @wraps(function) 
    @login_required 
    def decorateur(request, *k, **a): 
     if request.user.get_profile().site1 or request.user.is_superuser: 
      return function(request, *k, **a) 
     else: 
      result = error403(request) 
      return HttpResponseForbidden(result) 
    return decorateur 
    return function 

puis sur chaque vue y ou ajouter le décorateur, si l'utilisateur n'est pas autorisé à se connecter sur ce site, il recevra une erreur http403.

+0

Comme je l'ai commenté plus haut, je pense que je vais revenir à quelque chose de semblable, ne gâchera pas avec le modèle auth.user, ajoutera un manytomanyfield (Site) dans mon profil utilisateur, et ajoutera quelques connexions sur les signaux de connexion/enregistrement pour attraper/rediriger les utilisateurs quand ils réutilisent un nom d'utilisateur. Merci a tous :) – fylb

Questions connexes