文章目录
- Cookie
- 实践
- 运行结果
- CSRF
- 防止CSRF
- Session
- 实践
Cookie
理论上,一个用户的所有请求燥作都应该属于同一个会话,而另一个用户的所有请求操作则应该属于另一个会话,二者不能混淆,而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
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
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
<!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
<!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<form action="" method="post"> {% csrf_token %} </form>
-
CSRF verification failed. Request aborted.
CSRF验证失败。请求中止。
Session
服务器端会话技术,依赖于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
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那条记录也会被删掉。