Django会话技术

文章目录


Cookie

python 复制代码
	理论上,一个用户的所有请求燥作都应该属于同一个会话,而另一个用户的所有请求操作则应该属于另一个会话,二者不能混淆,而web应用程序是使用HTTP协议传输数据的。HTTP协议是无状态的协议。一旦数据交换完毕,客户端与服务器端的连接就会关闭,再次交换数据需要建立新的连接。这就意味着服务器无法从连接上跟踪会话。要跟踪该会话,必须引入一种机制。
	Cookie就是这样的一种机制。它可以弥补HTTP协议无状态的不足。在Session出现之前,基本上所有的网站都采用Cookie来跟踪会话。
	Cookie实际上是一小段的文本信息。客户端请求服务器,如果服务器需要记录该用户状态,就使用response向客户端浏览器颁发一个Cookie。客户端浏览器会把Cookie保存起来。当浏览器再请求该网站时,浏览器把请求的网址连同该Cookie一同提交给服务器。服务器检查该Cookie,以此来辨认用户状态。服务器还可以根据需要修改Cookie的内容。
	由于HTTP是一种无状态的协议,服务器单从网络连接上无从知道客户身份。怎么办呢?就给客户端们颁发一个通行证吧,每人一个,无论谁访问都必须携带自己通行证。这样服务器就能从通行证上确认客户身份了。这就是Cookie的工作原理。

	cookie本身由服务器生成,通过Response将cookie写到浏览器上,下一次访问,浏览器会根据不同的规则携带cookie过来。
	注意:cookie不能跨浏览器,一般不跨域
	
	设置cookie(使用response设置)
		response.set_cookie(key,value[,max_age=None,expires=None])
			max_age:整数 单位为秒,指定cookie过期时间
					设置为None:浏览器关闭失效,默认值
			expires:指定过期时间,还支持datetime或timedelta,可以指定一个具体日期时间
				expires=datetime.datetime(2030, 1, 1, 2, 3, 4)
				或 datetime.datetime.now() + datetime.timedelta(days=10)

			注意:max_age和expries两个选一个指定
			# response.set_cookie( 'username', username, max_age=10)
			# response.set_cookie( "username", username1, expires=d)

获取cookie(使用request获取):
	request.COOKIES.get('username')
删除cookie(使用response删除):
	response.delete_cookie('username')

cookie存储到客户端
优点:
	数据存在在客户端,减轻服务器端的压力,提高网站的性能。
缺点:
	安全性不高: 在客户端机很容易被查看或破解用户会话信息

实践

新建一个项目 Day05DjangoPro02,我就不写连接数据库了

路由Day05DjangoPro02\urls.py

python 复制代码
from django.contrib import admin
from django.urls import path
from App.views import *

urlpatterns = [
    path('', index),
    path('index/', index, name='index'),
    path('login/', login, name='login'),
    path('logout/', logout, name='logout'),

    path('admin/', admin.site.urls),

]

App\views.py

python 复制代码
import datetime

from django.shortcuts import render, redirect, reverse, HttpResponse


# 注销、登出
def logout(request):
    # 不能直接return render重新渲染是不可以的,我们一定要重新进入index页面,所以要跳转一下,路由也要变
    response = redirect(reverse('index'))
    # 删除cookie:注销
    response.delete_cookie('userid')
    return response


# 首页
def index(request):
    # cookie
    userid = request.COOKIES.get('userid', 0)  # 如果没找到就默认给个0

    # 获取登录的用户(查数据库,这边就不写查数据库了)
    user = None
    if userid != 0:
        user = {'username': 'admin'}

    return render(request, 'index.html', {'user': user})


# 登录
def login(request):
    if request.method == 'GET':
        return render(request, 'login.html')
    elif request.method == 'POST':
        # 1.先接收前端提交过来的数据
        username = request.POST.get('username')
        password = request.POST.get('password')
        # 2. 登录验证
        # 查数据库,这边就不写数据库了
        if username == 'admin' and password == '123456':
            # 3. 设置cookie
            # 注意:a. cookie是存储在浏览器本地
            #      b. cookie不能跨域,不能跨浏览器
            #      c. cookie存储的内容是字符串,不能为中文,一般存储大小不要超过4KB
            #      d. cookie由后端生成创建,返回给前端保存
            response = redirect(reverse('index'))
            # response.set_cookie('userid', 666)  # 创建cookie
            # 默认设置是当前浏览器打开的时候,如果把整个浏览器关掉,再打开userid就会没有
            # 一般需要设置过期时间
            # response.set_cookie('userid', 999, max_age=7 * 24 * 3600)  # 7天 max_age:秒
            # response.set_cookie('userid', 555, expires=datetime.datetime(2023, 8, 31, 3, 4, 5))
            # 过期具体的日期 expires 2023.8.31 3小时4分5秒
            response.set_cookie('userid', 555, expires=datetime.datetime.now() + datetime.timedelta(days=10))  # 10天后的日期
            # 4. 跳转到登录页面
            return response
        return HttpResponse('登录失败,账号是admin,密码是123456')

templates\login.html

python 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录</title>
</head>
<body>
    <h2>登录</h2>
    <hr>
    <form action="" method="post">
        {% csrf_token %}
        <p>用户名:<input type="text" name="username" /></p>
        <p>密码:<input type="text" name="password" /></p>
        <p><button>登录</button></p>
    </form>
</body>
</html>

templates\index.html

python 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>首页</title>
</head>
<body>
    <h2>首页</h2>
    <hr>
    {% if user %}
        当前登录的用户:{{ user.username }}
         <a href="{% url 'logout' %}">注销</a>
    {% else %}
         <a href="{% url 'login' %}">登录</a>

    {% endif %}
</body>
</html>

运行结果

登录前:http://127.0.0.1:8000

登录成功,看cookie

点击注销,看cookie


CSRF

  • CSRF全拼为Cross Site Request Forgery,跨站请求伪造。
  • CSRF指攻击者盗用了你的身份,以你的名义发送恶意请求
    • 包括:以你名义发送邮件,发消息,盗取你的账号,甚至于购买商品,虚拟货币转账...
  • 造成的问题: 个人隐私泄露以及财产安全。

防止CSRF

  • Django下的CSRF预防机制
    django第一次响应来自某个客户端的请求时,会在服务器端随机生成一个 token,把这个 token 放在cookie里。然后每次 POST请求都会带上这个 token,这样就能避免被 CSRF攻击。
  • django在setting.py文件中有一个中间件CsrfViewMiddleware,django会在内部自动生成token,并且将token返回给前端。这个cookie主要是跟后台做校验的,在内部会自己做校验。
  • 方法一,不推荐,在setting.py文件中把中间件注释,

  • 方法2:在Post请求时,表单中添加 {% csrf_token %}

    通过自动加token的方式防止CSRF

    python 复制代码
    <form action="" method="post">
    	{% csrf_token %}
    </form>
  • CSRF verification failed. Request aborted.

    CSRF验证失败。请求中止。

Session

python 复制代码
服务器端会话技术,依赖于cookie.
	django中启用SESSION
		settings中
			INSTALLED_APPS:
				'django.contrib.sessions'
			MIDDLEWARE:
				'django.contrib.sessions.middleware.SessionMiddleware'
				
	基本操作
		设置Sessions值 (使用request设置)
			request.session['user_id'] = user.id
			request.session.set_expiry(86400) # 设置过期时间
		
		获取Sessions值
			get(key,default=None) 根据键获取会话的值
			username = request.session.get("user_id")
			#或 session_name = request.session["session_name"]
		
		删除Sessions值
			# 获取当前请求的session的key
			session_key = request.session.session_key
			del request.session[session_key]
			# request.session.delete(session_key)
			flush()	删除当前的会话数据并删除会话的cookie
		
		clear()	清除所有会话
		
		数据存储到数据库中会进行编码,使用的是Base64
	每个HttpRequest对象都有一个session属性,也是一个类字典对象

settings中本身就配置好了

生成迁移文件: python manage.py makemigrations

执行迁移: python manage.py migrate

Session数据存储到数据库中会进行编码,使用的是Base64。如果我们设置了Session数据库是有东西的。

实践

在之前上面写好的基础改一下,把cookie改成session。
App\views.py

python 复制代码
import datetime

from django.shortcuts import render, redirect, reverse, HttpResponse


# 注销、登出
def logout(request):
    # 不能直接return render重新渲染是不可以的,我们一定要重新进入index页面,所以要跳转一下,路由也要变
    response = redirect(reverse('index'))
    # 删除cookie:注销
    # response.delete_cookie('userid')

    # 删除session:注销
    session_key = request.session.session_key  # 得到的是当前session会话的sessionid(前端cookie存的sessionid的值)
    print(session_key)
    request.session.delete(session_key)  # 数据库里的session_key那条记录也会被删掉

    return response


# 首页
def index(request):
    # # cookie
    # userid = request.COOKIES.get('userid', 0)  # 如果没找到就默认给个0

    # session
    userid = request.session.get('userid', 0)  # 一般我们都设置默认值,默认给个0, 如果不设置就是None

    # 获取登录的用户(查数据库,这边就不写查数据库了)
    # user= UserModel.objects.filter(id=userid).first()
    #                          .filter(id=None)  会报错!!!
    user = None
    if userid != 0:
        user = {'username': 'admin'}

    return render(request, 'index.html', {'user': user})


# 登录
def login(request):
    if request.method == 'GET':
        return render(request, 'login.html')
    elif request.method == 'POST':
        # 1.先接收前端提交过来的数据
        username = request.POST.get('username')
        password = request.POST.get('password')
        # 2. 登录验证
        # 查数据库,这边就不写数据库了
        if username == 'admin' and password == '123456':
            response = redirect(reverse('index'))
            # # 3. 设置cookie
            # # 注意:a. cookie是存储在浏览器本地
            # #      b. cookie不能跨域,不能跨浏览器
            # #      c. cookie存储的内容是字符串,不能为中文,一般存储大小不要超过4KB
            # #      d. cookie由后端生成创建,返回给前端保存
            # response = redirect(reverse('index'))
            # # response.set_cookie('userid', 666)  # 创建cookie
            # # 默认设置是当前浏览器打开的时候,如果把整个浏览器关掉,再打开userid就会没有
            # # 一般需要设置过期时间
            # # response.set_cookie('userid', 999, max_age=7 * 24 * 3600)  # 7天 max_age:秒
            # # response.set_cookie('userid', 555, expires=datetime.datetime(2023, 8, 31, 3, 4, 5))
            # # 过期具体的日期 expires 2023.8.31 3小时4分5秒
            # response.set_cookie('userid', 555, expires=datetime.datetime.now() + datetime.timedelta(days=10))  # 10天后的日期

            # 3. 设置session
            request.session['userid'] = 888
            request.session.set_expiry(7 * 24 * 3600)  # 7天 max_age:秒

            # 4. 跳转到登录页面
            return response
        return HttpResponse('登录失败,账号是admin,密码是123456')

http://127.0.0.1:8000/login/

登录之后,我们可以看到生成了一个cookie,名字叫sessionid,所以说session是依赖于cookie,但是在cookie存的是sessionid,并且它的值是经过编码的


看sessionid这个值,跟数据库里session_key是对应的。session_data也是经过编码加密的,这个数据里面会存放我们刚刚添加的userid的值,expire_date是过期时间。真正的数据是存在后台的,所以我们说session是存在于服务器端的会话技术。

下次前端访问后端的时候,它会把sessionid传过来,sessionid传过来之后,我们也不会得到sessionid,你得到的还是我们刚刚添加的userid,在内部它会自动查数据库,并且把对应的userid的值取出来,所以存也好,取也好,django都做好了。

注销之后,数据库里的session_key那条记录也会被删掉。

相关推荐
无心水26 分钟前
Java时间处理封神篇:java.time全解析
java·开发语言·python·架构·localdate·java.time·java时间处理
吴秋霖1 小时前
【某音电商】protobuf聊天协议逆向
python·算法·protobuf
深藏功yu名1 小时前
Day24:向量数据库 Chroma_FAISS 入门
数据库·人工智能·python·ai·agent·faiss·chroma
cm6543201 小时前
用Python破解简单的替换密码
jvm·数据库·python
wan9yu2 小时前
为什么你需要给 LLM 的数据"加密"而不是"脱敏"?我写了一个开源工具
python
摇滚侠2 小时前
你是一名 java 程序员,总结定义数组的方式
java·开发语言·python
这个名有人用不2 小时前
解决 uv 虚拟环境使用 pip 命令提示command not found的办法
python·pip·uv·claude code
Oueii2 小时前
掌握Python魔法方法(Magic Methods)
jvm·数据库·python
2501_908329853 小时前
使用Python自动收发邮件
jvm·数据库·python