Django笔记三十二之session登录验证操作

这篇具有很好参考价值的文章主要介绍了Django笔记三十二之session登录验证操作。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

本文首发于公众号:Hunter后端

原文链接:Django笔记三十二之session登录验证操作

这一篇笔记将介绍 session 相关的内容,包括如何在系统中使用 session,以及利用 session 实现登录认证的功能。

这篇笔记将分为以下几个内容:

  1. session 的使用流程
  2. session 的配置和相关方法
  3. users 模块的准备
  4. session 验证的的实现
  5. Session 表介绍
  6. 登录验证的几种实现形式

1、session 的使用流程

cookie 和 session 的基本概念这里不做赘述,这里简单讲一下在 Django 中如何使用自定义的模块来实现登录、登出以及仅允许登录用户访问某些接口的操作。

Django 有一套自带的 auth 验证模块,包括用户以及用户及相应的权限的表和操作,我们这里没有用,而是单独自定义一个 user 模块以及相应的功能函数用来实现用户的注册、登录和登出功能。

session 在这里的使用流程大致如下:

1、通过 login 接口,验证成功后,将某些信息写入 session,可以是 user_id,或者是某个你自定义的特定的字段,反正是后续需要进行验证是否登录成功的数据

2、在访问特定的、需要登录才可查看的接口前,先检查前端返回的数据中是否包含我们在上一步中写入的数据来确保用户是处于登录状态,如果是,则允许继续访问,否则返回未登录的信息,提示用户需要先进行登录操作

3、通过 logout 接口,将用户在 login 接口里写入的登录信息抹除,返回登出成功信息

在 Django 中,系统自动为我们准备好了 session 的所有相关的操作,我们只需要在后续的登录操作中往里面写入我们需要验证的数据即可。

Django 这部分为我们准备好的 session 操作也是通过中间件的形式存在的,是 settings.py 的 MIDDLEWARE 的 'django.contrib.sessions.middleware.SessionMiddleware'

如果不指定其他存储方式,session 的数据默认存在于我们的后端表中,这个我们在第一次执行 migrate 的时候已经自动为我们创建了该表,名为 django_session

表数据的操作和查看我们在后面再详细介绍。

2、session 的配置和相关方法

前面已经介绍了 session 的操作流程,这里我们介绍一下 session 的相关配置和方法。

session 配置

以下设置都在 settings.py 中设置,事实上,这些 session 的默认配置就差不多可以使用,后续有特殊需求我们可以再来查看,这里只介绍几个我觉得方便我们使用的。

这个地方的官方文档地址在:https://docs.djangoproject.com/zh-hans/3.2/ref/settings/#sessions

SESSION_COOKIE_AGE

session 过期时间,默认为 1209600,即 14 * 24 * 60 * 60,为 14天。

我们可以在 settings.py 中配置 session 的过期时长,也可以在程序中使用方法手动配置过期时长,方法的使用我们后面再介绍。

SESSION_COOKIE_NAME

默认值为 sessionid,在用户登录之后,请求我们系统,请求的 cookie 里会带上 session key-value 的参数,这个 key 就是我们这里的 SESSION_COOKIE_NAME,默认为 sessionid。

如果想改成其他的名称直接定义即可。

SESSION_ENGING

Django 存储 session 具体数据的地方,默认值为 django.contrib.sessions.backends.db,表示存在于数据库,也就是我们前面说的在 django_session 这张表。

也可以存储在文件或者缓存里。

session 方法

这里接着介绍一下 session 相关的方法,这些方法的调用一般是在接口里通过 request.session 来操作。

这里我们只是做一下方法的作用和效果的介绍,具体用途我们在之后的示例中再详细说明。

dict 操作

我们可以将 request.session 视作一个 dict,往里面添加 user_id,is_login 等用于标识用户是否登录的信息的时候可以直接操作,比如:

request.session["user_id"] = 1
request.session["is_login"] = True

keys()

输出 request.session.keys() 返回的就是我们在前面往 session 里添加的数据。

同理,request.session.items() 输出的也是我们往里添加的数据的 key-value 的值。

del 操作

当我们使用登出操作时,可以直接使用:

del request.session["user_id"]

这种方式会删除 session 中我们保存的 user_id 信息,这样用户在访问我们的接口的时候,如果我们做登录验证的操作,就会找不到已经登录的信息。

之前我们说过,我们的 session 数据会保存在数据库里,这种方式仅仅是删除 session 中某个特定的 key-value,并不会删除 django_session 表中这条数据

而如果想要直接删除这一条 session 数据,则可以使用 flush() 方法

flush()

下面的操作则会直接操作数据库删除这条 session 数据:

request.session.flush()

flush() 和 前面的 del 方法都可以用作我们 logout 过程中的操作。

get_expiry_age()

获取 session 过期秒数,这个值就是前面我们在 settings.py 中设置的 SESSION_COOKIE_AGE 的值。

clear_expired()

从 django_session 中移除过期的会话,下面会介绍 Session 这个 model 的相关操作,这里提前说一下这个函数。

django_session 会有一个 expire_date 字段,clear_expired() 这个操作就会删除表里 expire_date 小于当前时间的数据。

3、users 模块的准备

前面介绍了 session 的相关配置和方法以及 session 的基本使用流程。接下来我们将介绍如何在系统中使用上 session。

在介绍 session 使用前,我们自定义一个 users application 来做一下相关准备。

新建一个 application 和 相关的配置,在前面的笔记中都有介绍,这里不再做赘述,比如 app 的创建、在 settings.py 里 INSTALLED_APPS 里的定义,和 hunter/urls.py 的 patterns 里新建一条数据,指向 users/urls.py 等操作。

其中,在 hunter/urls.py 中对 users app 的 url 前缀我们定义为 users,如下:

# hunter/urls.py
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('blog/', include('blog.urls')),
    path('users/', include('users.urls')),
]

我们这里在 users/models.py 下新建一个 User model,然后对其进行相关的 migration 操作,使其表添加到数据库中。

# users/models.py

from django.db import models


class User(models.Model):
    username = models.CharField(max_length=20, verbose_name="登录用户名", unique=True)
    password = models.CharField(max_length=256, verbose_name="加密密码")

4、session 验证的的实现

接下来,我们将新建几个接口:

  • 用户注册接口
  • 用户登录接口
  • 用户注销接口
  • 用户信息接口

可以先看下这几个接口的代码总揽,接着我们详细介绍一下接口的操作。

users/urls.py

from django.urls import path
from users.views import LoginView, RegisterView, LogoutView, UserInfoView

urlpatterns = [
    path("register", RegisterView.as_view()),
    path("login", LoginView.as_view()),
    path("logout", LogoutView.as_view()),
    path("user/info", UserInfoView.as_view()),
]
users/views.py

from django.contrib.auth.hashers import make_password, check_password
from django.http import JsonResponse
from django.views import View
from users.models import User
import json


# 用户注册
class RegisterView(View):
    def post(self, request):
        request_json = json.loads(request.body)
        username = request_json.get("username")
        password = request_json.get("password")

        if not username or not password:
            result = {"code": -1, "msg": "username or password not valid"}
        else:
            if User.objects.filter(username=username).exists():
                result = {"code": -1, "msg": "username exists"}
            else:
                User.objects.create(username=username, password=make_password(password))
                result = {"code": 0, "msg": "success"}
        return JsonResponse(result, safe=False)


# 用户登录
class LoginView(View):
    def post(self, request):
        request_json = json.loads(request.body)
        username = request_json.get("username")
        password = request_json.get("password")

        if not username or not password:
            result = {"code": -1, "msg": "login info error"}
        else:
            user = User.objects.filter(username=username).first()
            if not user:
                result = {"code": -1, "msg": "username not found"}
            else:
                if check_password(password, user.password):
                    result = {"code": 0, "msg": "success"}
                    request.session["username"] = username
                else:
                    result = {"code": -1, "msg": "password error"}

        return JsonResponse(result, safe=False)


# 用户登出
class LogoutView(View):
    def post(self, request):
        if request.session.get("username"):
            del request.session["username"]
            # request.session.flush()
        return JsonResponse({"code": 0, "msg": "登出成功"})


# 用户信息
class UserInfoView(View):
    def post(self, request):
        username = request.session.get("username")
        if username:
            result = {"code": 0, "msg": f"登录用户为{username}"}
            status = 200
        else:
            result = {"code": -1, "msg": "用户未登录"}
            status = 401
        return JsonResponse(result, status=status)

首先介绍一下,所有请求的参数都是放在 body 里以 json 格式传递,我这里都是通过 postman 来请求测试的。

其次,在请求里,session 的处理可以直接通过 request.session 的方式进行,以下见示例。

用户注册接口

在注册接口里,这里做了参数校验的简化,直接 json.loads() 处理 body 的内容,然后通过 Django 自带的加密函数 make_password 将密码以加密的形式保存。

用户登录接口

登录接口里,首先是校验账号密码是否正确,判断正确后我们将登录用户的 username 字段写入 session,然后在用户下一次请求的时候就会自动获取该 session。

或者更正确的来说,用户登录在操作 request.session 之后,在返回 response 的时候,系统会在 django_session 里新增或者更新该用户的记录,这条数据有包含 session_key,session_data 和 expire_date 这几个字段。

session_key,在 cookie 的名称是 sessionid,postman 中第一次登录之后,在之后的每一次接口请求都会将sessionid=xx 传给后端,后端就会根据这个 session_key 的值去 django_session 表里查询相应的记录

如果这个 session_key 在表里不存在记录,或者 expire_date 过期了,那么后端系统会自动给其值赋为 None,即认定此次接口请求是未登录状态。

expire_date 字段则是一个时间字段,主要用于判断数据是否过期。

session_data 则是会包含我们写入的数据,比如我们在用户登录的时候,通过 request.session["username"] = username 的方式写入了一些特殊的标识,然后将其编码成 session_data 的值存入数据库,那么用户在下次请求接口的时候我们就可以通过解码 session_data,将值取出来用于判断用户是否登录。

将 session_data 解码的方式可以单独通过获取 django_session 的记录然后获取,但是在请求中,Django 为我么做了这些解码工作,我们可以直接通过前面介绍的 request.session.items() 的方式来查看在当前登录的 session_data 里写入的 key-value 数据。

注意: 前后端并不直接将 session_data 作为值传递,而是会传递 session_key 这个参数,一些校验的数据也都是放在 session_key 对应记录的 session_data 中存在后台的数据库中。

用户信息接口

我们假定获取用户信息接口要求用户必须处于登录状态,实际上也是,因为用户不登录无法定位到用户,然后获取用户的信息。

那么我们在进行下一步的实际操作前,我们肯定需要尝试从 session 中获取用户相应的信息,如果获取到了,则判断是处于登录状态,否则是处于未登录状态,无法获取用户信息。

所以我们这里的判断是从 session 中获取 username 字段,通过判断 username 是否有值来判断用户是否处于登录状态。

用户注销接口

用户注销,也就是登出接口,我们这里用的是 del 的方式,这个主要是看我们验证用户登录的方式,比如我们是通过向 session 中取值 username 来判断用户是否登录,那么 del request.session["username"] 的操作即可实现注销的功能。

注意: 这里执行的 del 操作仅仅是删除 session_data 中的 {"username": "xxx"} 的数据,这条 session_key 对应的数据还存在。

可以看到,在这条代码的下一行还有一条是执行的 flush() 操作,这个操作是直接在数据库里删除这条 session 记录,这是一种更为彻底的登出操作。

这里还需要注意的一点是,del 操作的前提是 session 数据里必须要有 username 这个 key,否则会引起报错,所以我们这里用了一个 if 判断逻辑,我们还可以使用 try-except 操作,或者更为彻底的操作是直接使用 flush() 操作。

至此,用户登录登出以及 session 数据的基本使用操作就介绍完毕了,下面我们额外介绍一些操作。

5、Session 表介绍

django_session 表的单独获取查看操作一般在程序里不会出现,因为前后端都是通过 cookie 中 sessionid 直接获取到对应的数据,但为了以防万一,或者你对这张表有一些兴趣,这里额外介绍一下如何单独操作这张表里的数据。

django_session 表的引入方式如下:

from django.contrib.sessions.models import Session

然后通过 session_key 来获取这条数据,比如 session_key 为 nqu3s71e38279bl5cbgju6sut64tnqmx,就可以:

session_key = "nqu3s71e38279bl5cbgju6sut64tnqmx"

session = Session.objects.get(pk=session_key)
# session = Session.objects.get(session_key=session_key)

其中,我们向 session 里写入的数据都包含在 session.session_data 里,我么可以直接通过 get_decoded() 方法来获取:

session.get_decoded()

# {'username': 'root'}

6、登录验证的几种实现形式

获取用户信息这个接口需要用户登录才可以接着获取用户信息,我们这里的操作是直接判断 session 里是否含有 username 字段。

但是如果我们系统里大部分接口都是需要用户先登录才可访问,这样在每个 views 里都要先加这个判断的操作,这样的显然是不实际的。

那么我们可以怎么操作来实现这个重复性的操作呢?

这里提供两个方式,一个是装饰器,一个是写在中间件里。

装饰器实现登录验证

其实如果直接使用 Django 自带的登录验证的功能,是可以直接使用系统自带的装饰器的,但是我们这里的表都是手动操作的,所以这个功能的装饰器我这里就自己实现了一个,相关代码如下:

def login_required_manual(func):
    def wrapper(*args, **kwargs):
        request = args[1]
        if not request.session.get("username"):
            return JsonResponse({"code": -1, "msg": "not login"}, status=401)
        return func(*args, **kwargs)
    return wrapper


class UserInfoView(View):
    @login_required_manual
    def post(self, request):
        username = request.session.get("username")
        return JsonResponse({"code": 0, "msg": f"登录用户{username}"})

可以看到,使用了登录验证的装饰器之后,我们的代码都简洁了很多。

我们可以尝试在调用登出接口后,再调用用户信息接口,可以看到系统就自动返回了未登录的信息了。

中间件实现登录验证

这里我们假定目前仅仅是注册和登录不需要登录即可访问,然后我们创建一个中间件如下:

# hunter/middlewares/auth_middleware.py

from django.http import JsonResponse

class AuthMiddleware:

    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        path = request.path

        # url 路径为 /users/register 和 /users/login 的接口不需要进行判断验证
        if path not in [
            "/users/register",
            "/users/login",
        ]:
            session = request.session
            if not session.get("username"):
                return JsonResponse({"code": -1, "msg": "not login"}, status=401)

        response = self.get_response(request)
        return response

然后在 hunter/settings.py 里加上这个中间件:

# hunter/settings.py

INSTALLED_APPS = [
    ...
    'hunter.middlewares.auth_middleware.AuthMiddleware',
    ...
]

这样,在每个接口请求到达 views 视图前,都会经历这个验证的中间件,这里将接口路径的判断简化成注册接口和登录接口,这两个接口不需要登录即可访问,其他接口都设置成需要登录才可访问。

相比于装饰器的做法,这里更推荐中间件的操作方式,这样首先就不用在每个 views 前加上装饰器,另外,需要登录才可访问的接口都可以在中间件部分统一列举出来,方便查看。

以上就是本篇笔记关于 session 的全部内容。

如果想获取更多后端相关文章,可扫码关注阅读:
Django笔记三十二之session登录验证操作文章来源地址https://www.toymoban.com/news/detail-427279.html

到了这里,关于Django笔记三十二之session登录验证操作的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java中基于Session登录验证

    基于Session的登录验证方式是最简单的一种登录校验方式。 为啥能用Session作为登录验证的一种方式,因为每个用户的请求都会有一个Session,这个对象是 Servlet 给我们创建的,不需要我们手动创建,并且这个对象的作用域为整个 Web 页面,也就是在整个项目中,这个 Session 可以

    2024年02月20日
    浏览(31)
  • 快速上手Django(七) -Django之登录cookie和session

    会话(Session)跟踪是Web程序中常用的技术,用来跟踪用户的整个会话。常用的会话跟踪技术是Cookie与Session。Cookie通过在客户端记录信息确定用户身份,Session通过在服务器端记录信息确定用户身份。 cookie Cookie原理、Set-Cookie常用字段、应用 参考URL: https://blog.csdn.net/jiangshangc

    2023年04月20日
    浏览(61)
  • 4.php开发-个人博客项目&登录验证&cookie&session&验证码安全​

    目录 知识点 本节大纲思路 ——这里以我自己的为例—— cookie验证—————— login1.php-登录后台界面 login_check.php-检查,作为包含文件 add_news.php-后台界面 php编码 如何创建 Cookie?--setcookie() 语法 实例 1 php header跳转 演示案例-cookie验证脆弱问题 session验证—————— sess

    2024年01月25日
    浏览(47)
  • 4.php开发-个人博客项目&登录验证&cookie&session&验证码安全

    目录 4.php开发-个人博客项目登录验证cookiesession验证码安全 知识点 本节大纲思路 ——这里以我自己的为例—— cookie验证—————— login1.php-登录后台界面 login_check.php-检查,作为包含文件 add_news.php-后台界面 php编码 如何创建 Cookie?--setcookie() 语法 实例 1 php header跳转 演示

    2024年01月23日
    浏览(47)
  • Django操作cookie、Django操作session、Django中的Session配置、CBV添加装饰器、中间件、csrf跨站请求

    1 Django操作cookie 2 Django操作session 3 Django中的Session配置 4 CBV添加装饰器 5 中间件 6 csrf跨站请求 6.1 使用django官方提供的js文件进行csrf认证

    2024年02月13日
    浏览(47)
  • 小迪安全 第15天:php开发-个人博客项目&登录验证&cookie&session&验证码安全

    1.后台验证-登录用户逻辑安全-怎么去判定用户登陆成功 2.后台验证-COOKIESESSION 3.后台验证-验证码·万能密码等 思路: 1.发送登录请求 账号 密码 2.接收账号密码 3.判断账号密码的准确性 正确 成功登陆-跳转成功页面 错误 失败登录-重新登陆 后台管理系统有多个文件页面,为了

    2024年04月15日
    浏览(75)
  • Node.js | 详解 Cookie-Session登录验证 的工作原理

    🧑‍💼 个人简介:一个不甘平庸的平凡人🍬 🖥️ 本系列专栏:Node.js从入门到精通 👉 你的一键三连是我更新的最大动力❤️! 📢 欢迎私信博主加入前端交流群🌹 目前绝大多数的系统都少不了 登录验证 的功能,这主要是为了保存用户的状态,以此来限制用户的各种行

    2024年01月17日
    浏览(37)
  • Django用户登录验证和自定义验证类

    用户登录时,使用 authenticate 验证用户名和密码是否正确,正确则返回一个用户对象。 用户名默认的字段名是 username 密码默认的字段名是 password 将已验证的用户添加到当前会话(session)中,可使用 login() 函数完成。 注意,如果用户未登录,logout() 不会报错。 调用 logout() 后,

    2024年02月14日
    浏览(42)
  • 【Redis】2、Redis应用之【根据 Session 和 Redis 进行登录校验和发送短信验证码】

    🌼 文章基于 B 站黑马程序员视频教程编写 🌼 做笔记便于日后复习 ① 手机号格式后端校验 手机号校验的正则表达式 校验工具类: ② 生成短信验证码 🌼 hutool 工具的详细使用: https://doc.hutool.cn/pages/index/ 🌿 根据 Cookie 中的 JSESSIONID 获取到 Session 🌿 然后从 Session 中获取到

    2024年02月11日
    浏览(58)
  • Django笔记三十八之发送邮件

    本文首发于公众号:Hunter后端 原文链接:Django笔记三十八之发送邮件 这一篇笔记介绍如何在 Django 中发送邮件。 在 Python 中,提供了 smtplib 的邮件模块,而 Django 在这个基础上对其进行了封装,我们可以通过 django.core.mail 来调用。 以下是本篇笔记的目录: 邮件配置项 send_m

    2024年02月03日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包