主机管理+堡垒机系统开发:自定义用户认证(三)

一、开发目标

1、引子

class UserProfile(models.Model):
    """堡垒机的账户"""
    user = models.OneToOneField(User)
    name = models.CharField(max_length=64)
    bind_hosts = models.ManyToManyField("BindHost",blank=True)
    host_groups = models.ManyToManyField(HostGroup)
     
    def __str__(self):
        return self.name

真正你在生产中不是这这么玩的,要完全自定制
自定制就是把class User(AbstractUser)这个表重写了,把他去掉之直接继承下面的

class AbstractUser(AbstractBaseUser, PermissionsMixin):

2、class AbstractUser表的的字段都在哪里 

1、AbstractBaseUser类代码

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']

2、后台web截图

3、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

4、截图

二、Specifying a custom User model(指定自定义用户模型)

1、自定义参考官方说明

https://docs.djangoproject.com/en/2.1/topics/auth/customizing/

https://www.cnblogs.com/ccorz/p/Django-zi-ding-yi-yong-hu-ren-zheng-xi-tong-zhi-zi.html

使用Django自定义用户模型必须满足:

  1. 模型必须有一个唯一的字段,可用于识别目的。

  2. 用户给定名称为“短”的标识,用户的全名为“长”标识符。他们可以返回完全相同的值。

     构建一个符合用户自定义模型的最简单的方法是继承abstractbaseuser类。abstractbaseuser提供一个用户模型的核心实现,包括密码和符号密码重置。Django自带用用户认证User也是继承了它。一些关键的实现细节:

class models.CustomUser

USERNAME_FIELD

2、必须有一个唯一标识--USERNAME_FIELD

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

REQUIRED_FIELDS

3、创建superuser时的必须字段

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

abstractbaseuser提供的方法

is_active(),is_authenticated()......

4、自定义models

class UserProfile(AbstractBaseUser,PermissionsMixin):
"""堡垒机的账户"""

    email = models.EmailField(
        verbose_name='email address',
        max_length=255,
        unique=True,
    )
    name = models.CharField(max_length=64)
    is_active = models.BooleanField(default=True)
    is_admin = models.BooleanField(default=False)
    is_staff = models.BooleanField(
        ('staff status'),
        default=False,
        help_text=('Designates whether the user can log into this admin site.'),
    )

    bind_hosts = models.ManyToManyField("BindHost",blank=True)
    host_groups = models.ManyToManyField("HostGroup",blank=True)

    objects = UserProfileManager()

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['name',]

5、settings中添加models文件名

AUTH_USER_MODEL = 'customauth.MyUser'

Django会去models中找这个类,所以要在原生的models.py中导入这个类。

三、代码实现

1、models.py

class UserProfile(AbstractBaseUser,PermissionsMixin):
"""堡垒机的账户"""

    email = models.EmailField(
        verbose_name='email address',
        max_length=255,
        unique=True,
    )
    name = models.CharField(max_length=64)
    is_active = models.BooleanField(default=True)
    is_admin = models.BooleanField(default=False)
    is_staff = models.BooleanField(
        ('staff status'),
        default=False,
        help_text=('Designates whether the user can log into this admin site.'),
    )

    bind_hosts = models.ManyToManyField("BindHost",blank=True)
    host_groups = models.ManyToManyField("HostGroup",blank=True)

    objects = UserProfileManager()

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['name',]

2、settings.py

虽然你自定定义了表结构,但是你没有明确的告诉django请用我用我自定的表结构,怎么告诉它?

AUTH_USER_MODEL = 'web.UserProfile'

3、admin.py  

from asset import models
admin.site.register(models.UserProfile)

四、后台效果

1、初始化数据库,登录后台。此时密码是明文显示,如果想改密码怎么办?

你指能改自己的,改不了别人的,那要该如何实现了 ?

这时,需要自定义admin显示(官方都提供了)。你i自定义了认证,整个admin你都要自己完全自定义

admin.py代码

from django.contrib import admin

from web import models
# Register your models here.


from django import forms
from django.contrib import admin
from django.contrib.auth.models import Group
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from django.contrib.auth.forms import ReadOnlyPasswordHashField

from web.models import UserProfile


class 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 = UserProfile
        fields = ('email', 'name')

    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 user


class 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 = UserProfile
        fields = ('email', 'password', 'name', '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 UserProfileAdmin(BaseUserAdmin):
    # 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', 'name','is_staff', 'is_admin')
    list_filter = ('is_admin','is_staff')
    fieldsets = (
        (None, {'fields': ('email', 'password')}),
        ('Personal info', {'fields': ('name',)}),
        ('堡垒机主机授权', {'fields': ('bind_hosts','host_groups')}),
        ('Permissions', {'fields': ('is_admin','is_staff','user_permissions','groups')}),
    )
    # 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', 'name', 'password1', 'password2')}
        ),
    )
    search_fields = ('email',)
    ordering = ('email',)
    filter_horizontal = ('user_permissions','groups','bind_hosts','host_groups')

# Now register the new UserAdmin...
admin.site.register(models.UserProfile, UserProfileAdmin)
# ... and, since we're not using Django's built-in permissions,
# unregister the Group model from admin.
admin.site.unregister(Group)



class RemoteUserAdmin(admin.ModelAdmin):
    list_display = ('username','auth_type','password')


admin.site.register(models.Host)
admin.site.register(models.HostGroup)
admin.site.register(models.BindHost)
admin.site.register(models.RemoteUser,RemoteUserAdmin)
admin.site.register(models.IDC)
admin.site.register(models.Session)

2、fieldsets 是什么意思?

后端代码 :

    fieldsets = (
        (None, {'fields': ('email', 'password')}),
        ('Personal info', {'fields': ('name',)}),
        ('Permissions', {'fields': ('is_admin','is_staff','user_permissions','groups')}),
    )

后台截图:

是不是加了个蓝线,是为了美化好区分

3、add_fieldsets是什么?

代码

    add_fieldsets = (
        (None, {
            'classes': ('wide',),
            'fields': ('email', 'name', 'password1', 'password2')}
        ),

截图

是不是必须填写的字段呀 

4、定义完表结构注册完后,登陆发现登录界面是输入email

  

5、为什么登录不了?设置红框的就可以了

        

6、编辑用户:

7、更改密码:没有Group:​

    

8、如果没有继承PermissionsMixin类就不会会没有如下的的权限

 

原文地址:https://www.cnblogs.com/luoahong/p/9458474.html