国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計 > 正文

Django自定義用戶認(rèn)證系統(tǒng)Customizingauthentication

2019-11-14 17:32:00
字體:
供稿:網(wǎng)友

擴(kuò)展已有的用戶模型Extending the existing User model

有兩種方法來擴(kuò)展默認(rèn)的User Model而不用重寫自己的模型。如果你不需要改變存儲在數(shù)據(jù)庫中的字段,而只是需要改變Model的行為,您可以創(chuàng)建一個基于User的代理Model。允許的行為包括默認(rèn)的ordering,custom managers, 或者 custom model methods。

如果你想存儲與User有關(guān)的信息,可以使用一個OneToOneField字段關(guān)聯(lián)到一個存儲額外信息的Model。這一Model通常被稱為一個PRofile model模型,它可以用來存儲一些非驗證所需的信息。例如,你可以創(chuàng)建一個Model

from django.contrib.auth.models import Userclass Employee(models.Model):    user = models.OneToOneField(User)    department = models.CharField(max_length=100)

訪問:

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

如果需要將profile model的字段添加到admin管理界面的user頁面上,需要在應(yīng)用app的admin.py中定義InlineModelAdmin

from django.contrib import adminfrom django.contrib.auth.admin import UserAdminfrom django.contrib.auth.models import Userfrom my_user_profile_app.models import Employee# Define an inline admin descriptor for Employee model# which acts a bit like a singletonclass EmployeeInline(admin.StackedInline):    model = Employee    can_delete = False    verbose_name_plural = 'employee'# Define a new User adminclass UserAdmin(UserAdmin):    inlines = (EmployeeInline, )# Re-register UserAdminadmin.site.unregister(User)admin.site.register(User, UserAdmin)

這些profile models并不特別,只是與User Model有一個OneToOne鏈接。所以當(dāng)一個user實例創(chuàng)建時,profile model并不會自動創(chuàng)建。

重寫User模型Substituting a custom User model

有時候User Model并不適合你的網(wǎng)站,比如你要將email而不是username作為認(rèn)證標(biāo)識,這時候就需要重寫User Model。

首先,需要將settings中的默認(rèn)User Model覆蓋:

AUTH_USER_MODEL = 'myapp.MyUser'

引用Referencing the User model

如果AUTH_USER_MODEL已被重設(shè),那當(dāng)User Model通過ForeignKey或者M(jìn)anyToManyField訪問時,不能直接訪問,而是要通過AUTH_USER_MODEL來訪問:

from django.conf import settingsfrom django.db import modelsclass Article(models.Model):    author = models.ForeignKey(settings.AUTH_USER_MODEL)

指定Specifying a custom User model

最簡單的定制一個User Model的方法是繼承用戶類AbstractBaseUser。

源碼

@python_2_unicode_compatibleclass AbstractBaseUser(models.Model):    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 the identifying username for this User"        return getattr(self, self.USERNAME_FIELD)    def __str__(self):        return self.get_username()    def natural_key(self):        return (self.get_username(),)    def is_anonymous(self):        """        Always returns False. This is a way of comparing User objects to        anonymous users.        """        return False    def is_authenticated(self):        """        Always return True. This is a way to tell if the user has been        authenticated in templates.        """        return True    def set_password(self, raw_password):        self.password = make_password(raw_password)    def check_password(self, raw_password):        """        Returns a boolean of whether the raw_password was correct. Handles        hashing formats behind the scenes.        """        def setter(raw_password):            self.set_password(raw_password)            self.save(update_fields=["password"])        return check_password(raw_password, self.password, setter)    def set_unusable_password(self):        # Sets 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):        """        Returns 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()

一些關(guān)鍵的字段和方法:

USERNAME_FIELD

必需的。設(shè)置認(rèn)證標(biāo)識。設(shè)置成標(biāo)識的字段unique必須為True。

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

上面的例子中identifier即作為MyUser的認(rèn)證標(biāo)識。

REQUIRED_FIELDS

字段name組成的列表。當(dāng)創(chuàng)建superuser時用到的字段。

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

列表中不應(yīng)該包含USERNAME_FIELD字段和password字段。

is_active

AbstractBaseUser默認(rèn)為True。

get_full_name()

get_short_name()

AbstractBaseUser的子類必須定義的兩個方法。

下面為一些AbstractBaseUser的子類可以使用的方法:

get_username()
返回USERNAME_FIELD的值.

is_anonymous()
返回False。

is_authenticated()
返回True。檢查一個user是否已登錄。

set_password(raw_password)
設(shè)置密碼

check_password(raw_password)
檢查密碼是否正確

set_unusable_password()

設(shè)置user無密碼

has_usable_password()
Returns False if set_unusable_password() has been called for this user.

get_session_auth_hash()
返回密碼字段的HMAC. Used for Session invalidation on password change.

還需要為自己的User Model定義一個custom manager。

class models.CustomUserManager
    create_user(*username_field*, password=None, **other_fields)
接受username field和required字段來創(chuàng)建用戶。例如,如果使用email作為username field, date_of_birth作為required field:

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

  create_superuser(*username_field*, password, **other_fields)

創(chuàng)建superuser

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

create_superuser中的password是必需的。

擴(kuò)展內(nèi)置的表單Custom users and the built-in auth forms

UserCreationForm

依賴于User Model. 擴(kuò)展User時必須重寫。

UserChangeForm

依賴于User Model. 擴(kuò)展User時必須重寫。

AuthenticationForm

Works with任何AbstractBaseUser子類 ,and will adapt to use the field defined in USERNAME_FIELD.

PasswordResetForm

Assumes that the user model has an integer primary key, has a field named email that can be used to identify the user, and a boolean field named is_active to prevent password resets for inactive users.

SetPasswordForm

Works with 任何AbstractBaseUser子類

PasswordChangeForm

Works with任何AbstractBaseUser子類

AdminPasswordChangeForm

Works with任何AbstractBaseUser子類。

定制admin功能Custom users and Admin

如果想自己定義的User Model能與admin管理系統(tǒng)一起使用,還需要定義一些字段和方法。

is_staff
是否允許user訪問admin界面

is_active
用戶是否活躍。

has_perm(perm, obj=None):
user是否擁有perm權(quán)限。

has_module_perms(app_label):
user是否擁有app中的權(quán)限

定制用戶和權(quán)限Custom users and permissions

如果要定制User的權(quán)限系統(tǒng),最簡單的方法是繼承PermissionsMixin

源碼:

class PermissionsMixin(models.Model):    """    A mixin class that adds the fields and methods necessary to support    Django's Group and Permission model using the ModelBackend.    """    is_superuser = models.BooleanField(_('superuser status'), default=False,        help_text=_('Designates that this user has all permissions without '                    'explicitly assigning them.'))    groups = models.ManyToManyField(Group, verbose_name=_('groups'),        blank=True, help_text=_('The groups this user belongs to. A user will '                                'get all permissions granted to each of '                                'their groups.'),        related_name="user_set", related_query_name="user")    user_permissions = models.ManyToManyField(Permission,        verbose_name=_('user permissions'), blank=True,        help_text=_('Specific permissions for this user.'),        related_name="user_set", related_query_name="user")    class Meta:        abstract = True    def get_group_permissions(self, obj=None):        """        Returns a list of permission strings that this user has through their        groups. This method queries all available auth backends. If an object        is passed in, only permissions matching this object are returned.        """        permissions = set()        for backend in auth.get_backends():            if hasattr(backend, "get_group_permissions"):                permissions.update(backend.get_group_permissions(self, obj))        return permissions    def get_all_permissions(self, obj=None):        return _user_get_all_permissions(self, obj)    def has_perm(self, perm, obj=None):        """        Returns True if the user has the specified permission. This method        queries all available auth backends, but returns immediately if any        backend returns True. Thus, a user who has permission from a single        auth backend is assumed to have permission in general. If an object is        provided, permissions for this specific object are checked.        """        # Active superusers have all permissions.        if self.is_active and self.is_superuser:            return True        # Otherwise we need to check the backends.        return _user_has_perm(self, perm, obj)    def has_perms(self, perm_list, obj=None):        """        Returns True if the user has each of the specified permissions. If        object is passed, it checks if the user has all required perms for this        object.        """        for perm in perm_list:            if not self.has_perm(perm, obj):                return False        return True    def has_module_perms(self, app_label):        """        Returns True if the user has any permissions in the given app label.        Uses pretty much the same logic as has_perm, above.        """        # Active superusers have all permissions.        if self.is_active and self.is_superuser:            return True        return _user_has_module_perms(self, app_label)

Django內(nèi)置的User對象就繼承了AbstractBaseUser和PermissionsMixin。

源碼:

class AbstractUser(AbstractBaseUser, PermissionsMixin):    """    An abstract base class implementing a fully featured User model with    admin-compliant permissions.    Username, password and email are required. Other fields are optional.    """    username = models.CharField(_('username'), max_length=30, unique=True,        help_text=_('Required. 30 characters or fewer. Letters, digits and '                    '@/./+/-/_ only.'),        validators=[            validators.RegexValidator(r'^[/w.@+-]+$',                                      _('Enter a valid username. '                                        'This value may contain only letters, numbers '                                        'and @/./+/-/_ characters.'), 'invalid'),        ],        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()    USERNAME_FIELD = 'username'    REQUIRED_FIELDS = ['email']    class Meta:        verbose_name = _('user')        verbose_name_plural = _('users')        abstract = True    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)class User(AbstractUser):    """    Users within the Django authentication system are represented by this    model.    Username, password and email are required. Other fields are optional.    """    class Meta(AbstractUser.Meta):        swappable = 'AUTH_USER_MODEL'

現(xiàn)在可以看一個完整的自定義User Model例子:

from django.db import modelsfrom 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 userclass 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 get_full_name(self):        # The user is identified by their email address        return self.email    def get_short_name(self):        # The user is identified by their email address        return self.email    def __str__(self):              # __unicode__ on Python 2        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

可以看到manager定義了create_user()和create_superuser()方法,MyUser定義了USERNAME_FIELD,REQUIRED_FIELDS字段和get_full_name(),get_short_name()方法,為了能與admin一起使用,還定義了is_active,is_staff,has_perm(),has_module_perms()

要在admin中注冊自定義的MyUser,還需要在app的admin.py中重寫UserCreationForm和UserChangeForm:

from django import formsfrom django.contrib import adminfrom django.contrib.auth.models import Groupfrom django.contrib.auth.admin import UserAdminfrom django.contrib.auth.forms import ReadOnlyPasswordHashFieldfrom customauth.models import MyUserclass 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(UserCreationForm, self).save(commit=False)        user.set_password(self.cleaned_data["password1"])        if commit:            user.save()        return userclass 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 MyUserAdmin(UserAdmin):    # 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, MyUserAdmin)# ... and, since we're not using Django's built-in permissions,# unregister the Group model from admin.admin.site.unregister(Group)

最后,別忘了在settings.py中定義AUTH_USER_MODEL:

AUTH_USER_MODEL = 'customauth.MyUser'

  


發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 沾化县| 满城县| 绩溪县| 潍坊市| 沙坪坝区| 温州市| 潮州市| 富平县| 呼伦贝尔市| 吉隆县| 长汀县| 庐江县| 崇左市| 墨脱县| 新营市| 西林县| 汝州市| 正阳县| 彭泽县| 乡城县| 定远县| 韶山市| 鹿邑县| 行唐县| 抚州市| 新宁县| 栾川县| 兴山县| 丰都县| 措勤县| 浙江省| 宁安市| 禄劝| 永州市| 宝清县| 永新县| 江陵县| 郑州市| 寿宁县| 和平县| 平湖市|