Django源码分析之权限系统_擒贼先擒王

简介:

乍见

Django内置的权限系统已经很完善了,加上django-guardian提供的功能,基本上能满足大部分的权限需求。暂且不说django-guardian,我们先来看下Django内置的权限系统:django.contrib.auth 包。

相识

一般权限系统分为全局权限和对象权限。Django只提供了一个对象权限的框架,具体实现由第三方库django-gardian完成。我们只看全局权限。

先来看auth包暴露出哪些接口。

django.contrib.auth.__init__.py

def load_backend(path):
    return import_string(path)()


def _get_backends(return_tuples=False):
    backends = []
    for backend_path in settings.AUTHENTICATION_BACKENDS:
        backend = load_backend(backend_path)
        backends.append((backend, backend_path) if return_tuples else backend)
    if not backends:
        raise ImproperlyConfigured(
            'No authentication backends have been defined. Does '
            'AUTHENTICATION_BACKENDS contain anything?'
        )
    return backends


def get_backends():
    return _get_backends(return_tuples=False)

前三个方法都是为了加载backends。一个backend其实就是一个class,必须实现authenticate和get_user两个方法。每当我们这样验证用户时

authenticate(username='username', password='password')

django就会去调用这些backend class,用其提供的方法去验证用户权限。那django是如何知道要调用哪些backend class呢?答案就在settings.py中,默认为

AUTHENTICATION_BACKENDS = ['django.contrib.auth.backends.ModelBackend']

那Django是如何调用这些backend class的呢?

def authenticate(**credentials):
    """
    If the given credentials are valid, return a User object.
    """
    for backend, backend_path in _get_backends(return_tuples=True):
        try:
            inspect.getcallargs(backend.authenticate, **credentials)
        except TypeError:
            # This backend doesn't accept these credentials as arguments. Try the next one.
            continue

        try:
            user = backend.authenticate(**credentials)
        except PermissionDenied:
            # This backend says to stop in our tracks - this user should not be allowed in at all.
            return None
        if user is None:
            continue
        # Annotate the user object with the path of the backend.
        user.backend = backend_path
        return user

    # The credentials supplied are invalid to all backends, fire signal
    user_login_failed.send(sender=__name__,
            credentials=_clean_credentials(credentials))

由此可见,Django会在第一个验证正确的backend class调用完成后停止,或者碰到PermissionDenied异常也会停止,所以backend class的顺序也很重要。可以添加自定义的backend class。

def login(request, user):
    """
    Persist a user id and a backend in the request. This way a user doesn't
    have to reauthenticate on every request. Note that data set during
    the anonymous session is retained when the user logs in.
    """
    session_auth_hash = ''
    if user is None:
        user = request.user
    if hasattr(user, 'get_session_auth_hash'):
        session_auth_hash = user.get_session_auth_hash()

    if SESSION_KEY in request.session:
        if _get_user_session_key(request) != user.pk or (
                session_auth_hash and
                request.session.get(HASH_SESSION_KEY) != session_auth_hash):
            # To avoid reusing another user's session, create a new, empty
            # session if the existing session corresponds to a different
            # authenticated user.
            request.session.flush()
    else:
        request.session.cycle_key()
    request.session[SESSION_KEY] = user._meta.pk.value_to_string(user)
    request.session[BACKEND_SESSION_KEY] = user.backend
    request.session[HASH_SESSION_KEY] = session_auth_hash
    if hasattr(request, 'user'):
        request.user = user
    rotate_token(request)
    user_logged_in.send(sender=user.__class__, request=request, user=user)

login方法,顾名思义,登录用户,同时设置好session,最后发送登入成功通知

def logout(request):
    """
    Removes the authenticated user's ID from the request and flushes their
    session data.
    """
    # Dispatch the signal before the user is logged out so the receivers have a
    # chance to find out *who* logged out.
    user = getattr(request, 'user', None)
    if hasattr(user, 'is_authenticated') and not user.is_authenticated():
        user = None
    user_logged_out.send(sender=user.__class__, request=request, user=user)

    # remember language choice saved to session
    language = request.session.get(LANGUAGE_SESSION_KEY)

    request.session.flush()

    if language is not None:
        request.session[LANGUAGE_SESSION_KEY] = language

    if hasattr(request, 'user'):
        from django.contrib.auth.models import AnonymousUser
        request.user = AnonymousUser()

相对的,logout方法,负责登出用户,清理session,最后设置当前用户为匿名用户

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
        )

Django不推荐直接使用User class,而是通知get_user_model方法获取当前的用户class(或者使用settins.AUTH_USER_MODEL)。这是为了防止因为开发者使用了自定义用户class而导致的信息错误。

def update_session_auth_hash(request, user):
    """
    Updating a user's password logs out all sessions for the user if
    django.contrib.auth.middleware.SessionAuthenticationMiddleware is enabled.

    This function takes the current request and the updated user object from
    which the new session hash will be derived and updates the session hash
    appropriately to prevent a password change from logging out the session
    from which the password was changed.
    """
    if hasattr(user, 'get_session_auth_hash') and request.user == user:
        request.session[HASH_SESSION_KEY] = user.get_session_auth_hash()

最后这个方法的使用场景很少。一般我们更新用户密码时,会在session中清除用户登录信息,导致用户需要重新登录。而使用update_session_auth_hash我们就可以在更新用户密码的同时更新用户的session信息,这样,用户就不需要重新登录了。

回想

擒贼先擒王,以上都是django.contrib.auth包中的__init__.py入口文件中的内容,背后还有很多“能工巧匠”,否则怎么支撑起auth整套权限系统?后续文章会一一介绍。

目录
相关文章
|
1月前
|
机器学习/深度学习 数据采集 数据可视化
基于爬虫和机器学习的招聘数据分析与可视化系统,python django框架,前端bootstrap,机器学习有八种带有可视化大屏和后台
本文介绍了一个基于Python Django框架和Bootstrap前端技术,集成了机器学习算法和数据可视化的招聘数据分析与可视化系统,该系统通过爬虫技术获取职位信息,并使用多种机器学习模型进行薪资预测、职位匹配和趋势分析,提供了一个直观的可视化大屏和后台管理系统,以优化招聘策略并提升决策质量。
|
1天前
|
机器学习/深度学习 人工智能 算法
植物病害识别系统Python+卷积神经网络算法+图像识别+人工智能项目+深度学习项目+计算机课设项目+Django网页界面
植物病害识别系统。本系统使用Python作为主要编程语言,通过收集水稻常见的四种叶片病害图片('细菌性叶枯病', '稻瘟病', '褐斑病', '稻瘟条纹病毒病')作为后面模型训练用到的数据集。然后使用TensorFlow搭建卷积神经网络算法模型,并进行多轮迭代训练,最后得到一个识别精度较高的算法模型,然后将其保存为h5格式的本地模型文件。再使用Django搭建Web网页平台操作界面,实现用户上传一张测试图片识别其名称。
30 21
植物病害识别系统Python+卷积神经网络算法+图像识别+人工智能项目+深度学习项目+计算机课设项目+Django网页界面
|
12天前
|
前端开发 搜索推荐 算法
中草药管理与推荐系统Python+Django网页界面+推荐算法+计算机课设系统+网站开发
中草药管理与推荐系统。本系统使用Python作为主要开发语言,前端使用HTML,CSS,BootStrap等技术和框架搭建前端界面,后端使用Django框架处理应用请求,使用Ajax等技术实现前后端的数据通信。实现了一个综合性的中草药管理与推荐平台。具体功能如下: - 系统分为普通用户和管理员两个角色 - 普通用户可以登录,注册、查看物品信息、收藏物品、发布评论、编辑个人信息、柱状图饼状图可视化物品信息、并依据用户注册时选择的标签进行推荐 和 根据用户对物品的评分 使用协同过滤推荐算法进行推荐 - 管理员可以在后台对用户和物品信息进行管理编辑
48 12
中草药管理与推荐系统Python+Django网页界面+推荐算法+计算机课设系统+网站开发
|
19小时前
|
机器学习/深度学习 算法 TensorFlow
交通标志识别系统Python+卷积神经网络算法+深度学习人工智能+TensorFlow模型训练+计算机课设项目+Django网页界面
交通标志识别系统。本系统使用Python作为主要编程语言,在交通标志图像识别功能实现中,基于TensorFlow搭建卷积神经网络算法模型,通过对收集到的58种常见的交通标志图像作为数据集,进行迭代训练最后得到一个识别精度较高的模型文件,然后保存为本地的h5格式文件。再使用Django开发Web网页端操作界面,实现用户上传一张交通标志图片,识别其名称。
22 6
交通标志识别系统Python+卷积神经网络算法+深度学习人工智能+TensorFlow模型训练+计算机课设项目+Django网页界面
|
1月前
|
监控 BI Python
python django教学质量评价系统,实现学生、教师、管理员不同角色管理
本文介绍了一个基于Django框架开发的教学质量评价系统,该系统为学生、教师和管理员提供了不同角色的管理和评价功能,实现了教学质量的全方位评估和管理,旨在提高教育质量和促进教学改革。
python django教学质量评价系统,实现学生、教师、管理员不同角色管理
|
1月前
|
人工智能 BI 数据处理
【优秀python django系统案例】基于python的医院挂号管理系统,角色包括医生、患者、管理员三种
本文介绍了一个基于Python开发的医院挂号管理系统,该系统包含医生、患者、管理员三种角色,旨在优化挂号流程,提高医疗服务质量和管理效率,并通过信息化手段提升患者就医体验和医院运营决策的数据支持能力。
【优秀python django系统案例】基于python的医院挂号管理系统,角色包括医生、患者、管理员三种
|
1月前
|
存储 关系型数据库 MySQL
基于python django 医院管理系统,多用户功能,包括管理员、用户、医生,数据库MySQL
本文介绍了一个基于Python Django框架开发的医院管理系统,该系统设计了管理员、用户和医生三个角色,具备多用户功能,并使用MySQL数据库进行数据存储和管理。
基于python django 医院管理系统,多用户功能,包括管理员、用户、医生,数据库MySQL
|
1月前
|
自然语言处理 前端开发 数据处理
Django的模板系统
【8月更文挑战第13天】
23 2
|
20天前
|
API Java 数据库连接
从平凡到卓越:Hibernate Criteria API 让你的数据库查询瞬间高大上,彻底告别复杂SQL!
【8月更文挑战第31天】构建复杂查询是数据库应用开发中的常见需求。Hibernate 的 Criteria API 以其强大和灵活的特点,允许开发者以面向对象的方式构建查询逻辑,同时具备 SQL 的表达力。本文将介绍 Criteria API 的基本用法并通过示例展示其实际应用。此 API 通过 API 构建查询条件而非直接编写查询语句,提高了代码的可读性和安全性。无论是简单的条件过滤还是复杂的分页和连接查询,Criteria API 均能胜任,有助于提升开发效率和应用的健壮性。
37 0
|
21天前
|
前端开发 数据处理 开发者
解锁Django模板系统终极奥义!揭秘高效前端渲染秘籍,让你的网站秒变炫酷黑科技!
【8月更文挑战第31天】Django作为Python的高级Web框架,内置的模板系统支持动态HTML渲染。本文通过在线书店案例,详细介绍Django模板系统的设置与高效渲染技巧,包括创建模板文件、编写视图函数及URL配置。通过合理使用过滤器、深度查询和模板继承等技巧,提升前端渲染效率和安全性,优化Web应用开发流程。
8 0