django.contrib.auth.backend-後臺

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
這裏它會去驗證返回的結果集,是有否相應app_label開頭。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章