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  后續我會提供: 注冊/驗證/登錄/注銷封裝好的類,感謝大家閱讀!!!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM