zoukankan      html  css  js  c++  java
  • Django中用户权限模块

    Django中用户权限模块

    1 auth模块

    auth模块是Django提供的标准权限管理系统,可以提供用户身份认证, 用户组和权限管理。
    auth可以和admin模块配合使用, 快速建立网站的管理系统。
    在INSTALLED_APPS中添加'django.contrib.auth'使用该APP, auth模块默认启用。
    

    2 User属性与方法

    (1) 属性
    User是auth模块中维护用户信息的关系模式(继承了models.Model), 数据库中该表被命名为auth_user.
    参照后续源码更清楚的了解User类继承的属性与方法.这里只是展示一部分.
    
    该数据表在数据库中:
    'auth_user'
    	"id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, 
        "password" varchar(128) NOT NULL, "last_login" datetime NULL, 
        "is_superuser" bool NOT NULL, 
        "first_name" varchar(30) NOT NULL, 
        "last_name" varchar(30) NOT NULL,
        "email" varchar(254) NOT NULL, 
        "is_staff" bool NOT NULL, 
        "is_active" bool NOT NULL,
        "date_joined" datetime NOT NULL,
        "username" varchar(30) NOT NULL UNIQUE
    一般当建立关联表时需要与User建立关联,则需要导入使用,比如建议OneToOne联系
    
    from django.contrib.auth.models import User
    class Profile(models.Model):
        user = models.OneToOneField(User)  #建立关联到User
        blog = models.CharField(maxlength=128, blank=True)
        location = models.CharField(maxlength=128, blank=True)
        occupation = models.CharField(maxlength=64, blank=True)
    (2) 方法
    is_anonymous():是否为匿名用户,如果你已经login,则这个方法返回始终为false.
    is_authenticated():是否通过验证,也就是通过用户名和密码判断该用户是否存在
    get_group_permissions():得到所有该用户所属组别的权限
    get_all_permissions():得到该用户所有的权限.
    has_perm(perm):判断用户是否具有特定权限,perm的格式是appname.codename
    email_user(subject, message, from_email=None):给某用户发送邮件
    
    例如创建一个superuser装饰器:
    
    #登录用户必须为超级用户,只能在类中使用
    def superuser_required(func):
        def _wrapper(self,request,*args,**kwargs):
            #User中包含了is_superuser属性
            if not request.user.is_superuser:
                #定义的未登录函数 not_authenticated()
                return not_authenticated()
            return func(self,request,*args,**kwargs)
        return _wrapper
    这里设置superuser当然也可以自己设置不同权限的装饰器,这样代码更加简单!!
    

    3 User常见的用法

    (1)  新建用户
    user = User.objects.create_user(username, password)
    user.save()  #保存数据库
    auth模块不存储用户密码明文而是存储一个Hash值
    
    (2) 验证登录
    from django.contrib.auth import login
    
    username = request.POST['username']
    password = request.POST['password']
    #login不进行认证,也不检查is_active标志位, 一般和authenticate配合使用:
    user = authenticate(username=username, password=password)
    if not user:
    	if user.is_active:
            return HttpResponse(json.dumps({
              'error':'用户名或者密码错误'
            }))
    login(request,user)
    
    login向session中添加SESSION_KEY, 便于对用户进行跟踪.
    首先我们要验证这个用户,然后再登陆,登陆成功后,我们可以通过request.user 来得到当前登陆的用户对象
    
    (3) 退出登录
    logout会移除request中user信息,并刷新session,清空cookie中sessionid
    from django.contrib.auth import logout
    
    def logout_view(request):
        logout(request)
       
    (4) 限制非法用户访问
    普通做法通过 request.user.is_authenticated()判定,返回重定向login登录界面
    from django.http import HttpResponseRedirect
    
    def my_view(request):
        if not request.user.is_authenticated():
            return HttpResponseRedirect('/login.html/')
    这种方法会造成重复判定问题
    
    简单做法采用装饰器语法糖搞定,django中封装了login_required
    from django.contrib.auth.decorators import login_required
    
    @login_required  #过滤掉非登录用户
    def my_view(request):
    	#限定为合法用户访问
    这样当你访问my_view的时候,就需要用户需要通过验证,不通过可以重定向来解决
    

    4 Group用户组

    django.contrib.auth.models.Group定义了用户组的模型, 每个用户组拥有id和name两个字段, 该模型在数据库被映射为auth_group数据表。
    
    User对象中有一个名为groups的多对多字段, 多对多关系由auth_user_groups数据表维护。Group对象可以通过user_set反向查询用户组中的用户。
    
    # 创建create
    group = Group.objects.create(name=group_name)
    group.save()
    
    #add
    用户加入用户组user.groups.add(group)或group.user_set.add(user)
    
    #remove
    用户退出用户组user.groups.remove(group)或group.user_set.remove(user)
    

    5 Permission

    Django的auth系统提供了模型级的权限控制, 即可以检查用户是否对某个数据表拥有增(add), 改(change), 删(delete)权限,但无法检查用户对某一篇博文是否拥有管理权限。
    
    user.has_perm('blog.add_article')
    user.has_perm('blog.change_article')
    user.has_perm('blog.delete_article')
    user.has_perm方法用于检查用户是否拥有操作某个模型权限,若拥有权限则返回True。仅是进行权限检查, 即是用户没有权限它也不会阻止程序员执行相关操作。
    
    permission_required修饰器可以代替has_perm并在用户没有相应权限时重定向到登录页或者抛出异常。
    # permission_required(perm[, login_url=None, raise_exception=False])
    
    #给blog中article添加权限,装饰器之后更加简单
    @permission_required('blog.add_article')
    def post_article(request):
        pass
    

    6 管理用户权限

    User和Permission通过多对多字段user.user_permissions关联,在数据库中由auth_user_user_permissions数据表维护,可以执行添加权限,删除权限,清空权限.
    

    7 User继承的父类

    User先继承AbstractUser类,该类的基类为AbstractBaseUser,有兴趣的了解下,可以更深入的发现User类的功能

    附上User继承类AbstractUser类的基类AbstractBaseUser的源码:
    
    class AbstractBaseUser(models.Model):
    	
    	'''
    	常见的子类User继承的属性:
    	password    密码
    	last_login  最后登录
    	is_active   是否在线
    	
    	常见定义的方法:
    	save  保存
    	is_authenticated  登录验证
    	set_password  设置密码
    	check_password   检查密码
    	'''
        password = models.CharField(_('password'), max_length=128)
        last_login = models.DateTimeField(_('last login'), blank=True, null=True)
    
        is_active = True
    
        REQUIRED_FIELDS = []
    
        class Meta:
            abstract = True
    
        def get_username(self):
            return getattr(self, self.USERNAME_FIELD)
    
        def __init__(self, *args, **kwargs):
            super(AbstractBaseUser, self).__init__(*args, **kwargs)
            self._password = None
    
        def __str__(self):
            return self.get_username()
    
        def clean(self):
            setattr(self, self.USERNAME_FIELD, self.normalize_username(self.get_username()))
    
        def save(self, *args, **kwargs):
            super(AbstractBaseUser, self).save(*args, **kwargs)
            if self._password is not None:
                password_validation.password_changed(self._password, self)
                self._password = None
    
        def natural_key(self):
            return (self.get_username(),)
    
        @property
        def is_anonymous(self):
            """
            Always return False. This is a way of comparing User objects to
            anonymous users.
            """
            return CallableFalse
    
        @property
        def is_authenticated(self):
            """
            Always return True. This is a way to tell if the user has been
            authenticated in templates.
            """
            return CallableTrue
    
        def set_password(self, raw_password):
            self.password = make_password(raw_password)
            self._password = raw_password
    
        def check_password(self, raw_password):
            """
            Return a boolean of whether the raw_password was correct. Handles
            hashing formats behind the scenes.
            """
            def setter(raw_password):
                self.set_password(raw_password)
                # Password hash upgrades shouldn't be considered password changes.
                self._password = None
                self.save(update_fields=["password"])
            return check_password(raw_password, self.password, setter)
    
        def set_unusable_password(self):
            # Set a value that will never be a valid hash
            self.password = make_password(None)
    
        def has_usable_password(self):
            return is_password_usable(self.password)
    
        def get_full_name(self):
            raise NotImplementedError('subclasses of AbstractBaseUser must provide a get_full_name() method')
    
        def get_short_name(self):
            raise NotImplementedError('subclasses of AbstractBaseUser must provide a get_short_name() method.')
    
        def get_session_auth_hash(self):
            """
            Return an HMAC of the password field.
            """
            key_salt = "django.contrib.auth.models.AbstractBaseUser.get_session_auth_hash"
            return salted_hmac(key_salt, self.password).hexdigest()
    
        @classmethod
        def get_email_field_name(cls):
            try:
                return cls.EMAIL_FIELD
            except AttributeError:
                return 'email'
    
        @classmethod
        def normalize_username(cls, username):
            return unicodedata.normalize('NFKC', force_text(username))
    
    User继承类AbstractUser类的源码:
    class AbstractUser(AbstractBaseUser, PermissionsMixin):
       '''
       继承该类常见属性有:
       username    用户名
       first_name  姓
       last_name   名
       email       邮箱
       '''
        username_validator = UnicodeUsernameValidator() if six.PY3 else ASCIIUsernameValidator()
    
        username = models.CharField(
            _('username'),
            max_length=150,
            unique=True,
            help_text=_('Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.'),
            validators=[username_validator],
            error_messages={
                'unique': _("A user with that username already exists."),
            },
        )
        first_name = models.CharField(_('first name'), max_length=30, blank=True)
        last_name = models.CharField(_('last name'), max_length=30, blank=True)
        email = models.EmailField(_('email address'), blank=True)
        is_staff = models.BooleanField(
            _('staff status'),
            default=False,
            help_text=_('Designates whether the user can log into this admin site.'),
        )
        is_active = models.BooleanField(
            _('active'),
            default=True,
            help_text=_(
                'Designates whether this user should be treated as active. '
                'Unselect this instead of deleting accounts.'
            ),
        )
        date_joined = models.DateTimeField(_('date joined'), default=timezone.now)
    
        objects = UserManager()
    
        EMAIL_FIELD = 'email'
        USERNAME_FIELD = 'username'
        REQUIRED_FIELDS = ['email']
    
        class Meta:
            verbose_name = _('user')
            verbose_name_plural = _('users')
            abstract = True
    
        def clean(self):
            super(AbstractUser, self).clean()
            self.email = self.__class__.objects.normalize_email(self.email)
    
        def get_full_name(self):
            """
            Returns the first_name plus the last_name, with a space in between.
            """
            full_name = '%s %s' % (self.first_name, self.last_name)
            return full_name.strip()
    
        def get_short_name(self):
            "Returns the short name for the user."
            return self.first_name
    
        def email_user(self, subject, message, from_email=None, **kwargs):
            """
            Sends an email to this User.
            """
            send_mail(subject, message, from_email, [self.email], **kwargs)
    

    注: 1 权限部分参考了原文:http://www.cnblogs.com/Finley/p/5575305.html 非常感谢!!

      2  后续我会提供: 注册/验证/登录/注销封装好的类,感谢大家阅读!!!
  • 相关阅读:
    Java ,python面向对象的继承及其区别
    谈谈我理解的敏捷开发
    Centos7 升级python3,解决升级后不兼容问题
    Django + Uwsgi + Nginx 的生产环境部署
    理解Python协程:从yield/send到yield from再到async/await
    【转】Python 数据库连接池
    为何GET只发一次TCP连接,POST发两次TCP连接
    Python简单密码加密程序,加盐(salt)md5
    spring学习(三) ———— spring事务操作
    spring学习(二) ———— AOP之AspectJ框架的使用
  • 原文地址:https://www.cnblogs.com/why957/p/9075601.html
Copyright © 2011-2022 走看看