auth模塊的驗證和用戶的信息,都是通過backend這個模塊來獲取的。
backend.py文件目前有兩個類,ModelBackend和RemoteUserBackend。
首先看ModelBackend的對外接口,
認證方面: authenticate
獲取用戶: get_user,
權限方面: get_user_permissions, get_group_permissions,get_all_permissions,has_perm, has_module_perms
認證方面:
首先看authenticate的定義:
1
2
3
4
5
6
7
8
9
10
11
12
|
def authenticate( self , username = None , password = None , * * kwargs): UserModel = get_user_model() if username is None : username = kwargs.get(UserModel.USERNAME_FIELD) try : user = UserModel._default_manager.get_by_natural_key(username) if user.check_password(password): return user except UserModel.DoesNotExist: # Run the default password hasher once to reduce the timing # difference between an existing and a non-existing user (#20760). UserModel().set_password(password) |
它首先調用get_user_model方法,獲取User模型。之所以要封裝在一個單獨的方法裏,是爲了做到User模型自定義。
下面是get_user_model的定義:
1
2
3
4
5
6
7
8
9
10
11
12
|
def get_user_model(): """ Returns the User model that is active in this project. """ try : return django_apps.get_model(settings.AUTH_USER_MODEL) except ValueError: raise ImproperlyConfigured( "AUTH_USER_MODEL must be of the form 'app_label.model_name'" ) except LookupError: raise ImproperlyConfigured( "AUTH_USER_MODEL refers to model '%s' that has not been installed" % settings.AUTH_USER_MODEL ) |
可以看到這個返回的User模型是由配置文件的AUTH_USER_MODEL屬性指定的。可以查看django.conf.global_settings (django的默認配置),AUTH_USER_MODEL的值爲'auth.User'。
看完get_user_model函數,再接着看authenticate方法。注意看它會獲取kwargs的UserModel.USERNAME_FIELD屬性,這是User模型的標識字段,以auth中的User模型爲例,它的標識字段就是username,然後User模型的objects會根據此標識字段,調用get_by_natural_key方法查詢user。關於User模型這一塊,下篇會詳細介紹。
authenticate的認證任務最後是交給user的check_password執行了。
獲取用戶:
然後看獲取用戶方面,get_user不同於上面的查詢,它是根據pk(即爲id)查詢。
1
2
3
4
5
6
|
def get_user( self , user_id): UserModel = get_user_model() try : return UserModel._default_manager.get(pk = user_id) except UserModel.DoesNotExist: return None |
權限方面:
權限的查詢,需要對auth的models有所瞭解。簡單的說一下models的結構:
Permission是表示權限的model,
Group是表示組的model,
User是表示用戶的model。
Permission與Group是多對多的關係,通過Group的字段(permission)指定。
User與Group是多對多的關係,通過User的字段(group)指定。
User與Permission是多對多的關係,通過User的字段(user_permissions)指定。
關於權限方面的方法,實質上就是數據庫的查詢。這裏涉及到User的權限和Group的權限。
1
2
3
4
5
6
7
|
def _get_user_permissions( self , user_obj): return user_obj.user_permissions. all () def _get_group_permissions( self , user_obj): user_groups_field = get_user_model()._meta.get_field( 'groups' ) user_groups_query = 'group__%s' % user_groups_field.related_query_name() return Permission.objects. filter ( * * {user_groups_query: user_obj}) |
_get_group_permissions是根據用戶所屬的組,查詢組的權限。
這裏model用的查詢api,涉及到雙下劃線的使用。上面首先會去獲取User和Group關聯的字段,然後獲取related_query_name,最後聯合查詢得到權限。
get_user_permissions和get_group_permissions只是調用了_get_permissions方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
def get_user_permissions( self , user_obj, obj = None ): """ Returns a set of permission strings the user `user_obj` has from their `user_permissions`. """ return self ._get_permissions(user_obj, obj, 'user' ) def get_group_permissions( self , user_obj, obj = None ): """ Returns a set of permission strings the user `user_obj` has from the groups they belong. """ return self ._get_permissions(user_obj, obj, 'group' ) |
_get_permissions方法只是起代理的作用:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
def _get_permissions( self , user_obj, obj, from_name): """ Returns the permissions of `user_obj` from `from_name`. `from_name` can be either "group" or "user" to return permissions from `_get_group_permissions` or `_get_user_permissions` respectively. """ if not user_obj.is_active or user_obj.is_anonymous() or obj is not None : return set () perm_cache_name = '_%s_perm_cache' % from_name if not hasattr (user_obj, perm_cache_name): if user_obj.is_superuser: perms = Permission.objects. all () else : perms = getattr ( self , '_get_%s_permissions' % from_name)(user_obj) perms = perms.values_list( 'content_type__app_label' , 'codename' ).order_by() setattr (user_obj, perm_cache_name, set ( "%s.%s" % (ct, name) for ct, name in perms)) return getattr (user_obj, perm_cache_name) |
它最終會調用_get_user_permissions和_get_group_permissions方法返回結果。其中也在user_obj中存儲了對應的緩存。
注意它將返回Permission對象,取出app_label(content_type爲外鍵),和codename屬性,並且通過點連接, 返回set結果集。
1
2
3
4
5
6
7
|
def get_all_permissions( self , user_obj, obj = None ): if not user_obj.is_active or user_obj.is_anonymous() or obj is not None : return set () if not hasattr (user_obj, '_perm_cache' ): user_obj._perm_cache = self .get_user_permissions(user_obj) user_obj._perm_cache.update( self .get_group_permissions(user_obj)) return user_obj._perm_cache |
get_all_permissions也只是組合了user和group對應的permission。
1
2
3
4
|
def has_perm( self , user_obj, perm, obj = None ): if not user_obj.is_active: return False return perm in self .get_all_permissions(user_obj, obj) |
has_perm用來驗證用戶權限的。
1
2
3
4
5
6
7
8
9
10
|
def has_module_perms( self , user_obj, app_label): """ Returns True if user_obj has any permissions in the given app_label. """ if not user_obj.is_active: return False for perm in self .get_all_permissions(user_obj): if perm[:perm.index( '.' )] = = app_label: return True return False |