Django用户认证(四)自定义认证Customizing authentication

原文:https://www.cnblogs.com/linxiyue/p/4061044.html

扩展已有的用户模型Extending the existing User model

有两种方法来扩展默认的User Model而不用重写自己的模型。如果你不需要改变存储在数据库中的字段,而只是需要改变Model的行为,您可以创建一个基于User的代理Model。允许的行为包括默认的ordering,custom managers, 或者 custom model methods。

如果你想存储与User有关的信息,可以使用一个OneToOneField字段关联到一个存储额外信息的Model。这一Model通常被称为一个profile model模型,它可以用来存储一些非验证所需的信息。例如,你可以创建一个Model:

1
2
3
4
5
from  django.contrib.auth.models  import  User
 
class  Employee(models.Model):
     user  =  models.OneToOneField(User)
     department  =  models.CharField(max_length = 100 )

访问:

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

如果需要将profile model的字段添加到admin管理界面的user页面上,需要在应用app的admin.py中定义InlineModelAdmin

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from  django.contrib  import  admin
from  django.contrib.auth.admin  import  UserAdmin
from  django.contrib.auth.models  import  User
 
from  my_user_profile_app.models  import  Employee
 
# Define an inline admin descriptor for Employee model
# which acts a bit like a singleton
class  EmployeeInline(admin.StackedInline):
     model  =  Employee
     can_delete  =  False
     verbose_name_plural  =  'employee'
 
# Define a new User admin
class  UserAdmin(UserAdmin):
     inlines  =  (EmployeeInline, )
 
# Re-register UserAdmin
admin.site.unregister(User)
admin.site.register(User, UserAdmin)

这些profile models并不特别,只是与User Model有一个OneToOne链接。所以当一个user实例创建时,profile model并不会自动创建。

重写User模型Substituting a custom User model

有时候User Model并不适合你的网站,比如你要将email而不是username作为认证标识,这时候就需要重写User Model。

首先,需要将settings中的默认User Model覆盖:

1
AUTH_USER_MODEL  =  'myapp.MyUser'

引用Referencing the User model

如果AUTH_USER_MODEL已被重设,那当User Model通过ForeignKey或者ManyToManyField访问时,不能直接访问,而是要通过AUTH_USER_MODEL来访问:

1
2
3
4
5
from  django.conf  import  settings
from  django.db  import  models
 
class  Article(models.Model):
     author  =  models.ForeignKey(settings.AUTH_USER_MODEL)

指定Specifying a custom User model

最简单的定制一个User Model的方法是继承用户类AbstractBaseUser。

源码:

一些关键的字段和方法:

USERNAME_FIELD

必需的。设置认证标识。设置成标识的字段unique必须为True。

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

上面的例子中identifier即作为MyUser的认证标识。

REQUIRED_FIELDS

字段name组成的列表。当创建superuser时用到的字段。

1
2
3
4
5
6
class  MyUser(AbstractBaseUser):
     ...
     date_of_birth  =  models.DateField()
     height  =  models.FloatField()
     ...
     REQUIRED_FIELDS  =  [ 'date_of_birth' 'height' ]

列表中不应该包含USERNAME_FIELD字段和password字段。

is_active

AbstractBaseUser默认为True。

get_full_name()

get_short_name()

AbstractBaseUser的子类必须定义的两个方法。

下面为一些AbstractBaseUser的子类可以使用的方法:

get_username()
返回USERNAME_FIELD的值.

is_anonymous()
返回False。

is_authenticated()
返回True。检查一个user是否已登录。

set_password(raw_password)
设置密码

check_password(raw_password)
检查密码是否正确

set_unusable_password()

设置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字段来创建用户。例如,如果使用email作为username field, date_of_birth作为required field:

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

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

创建superuser

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

create_superuser中的password是必需的。

扩展内置的表单Custom users and the built-in auth forms

UserCreationForm

依赖于User Model. 扩展User时必须重写。

UserChangeForm

依赖于User Model. 扩展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管理系统一起使用,还需要定义一些字段和方法。

is_staff
是否允许user访问admin界面

is_active
用户是否活跃。

has_perm(perm, obj=None):
user是否拥有perm权限。

has_module_perms(app_label):
user是否拥有app中的权限

定制用户和权限Custom users and permissions

如果要定制User的权限系统,最简单的方法是继承PermissionsMixin

源码:

Django内置的User对象就继承了AbstractBaseUser和PermissionsMixin。

源码:

现在可以看一个完整的自定义User Model例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
from  django.db  import  models
from  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  user
 
 
class  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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
from  django  import  forms
from  django.contrib  import  admin
from  django.contrib.auth.models  import  Group
from  django.contrib.auth.admin  import  UserAdmin
from  django.contrib.auth.forms  import  ReadOnlyPasswordHashField
 
from  customauth.models  import  MyUser
 
 
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  =  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  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  =  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:

1
AUTH_USER_MODEL  =  'customauth.MyUser'

  

猜你喜欢

转载自www.cnblogs.com/chdltanke/p/10365379.html