HTTP被设计为”⽆态”,也就是俗称“脸盲”。 这⼀次请求和下⼀次请求 之间没有任何状态保持,我们⽆法根据请求的任何⽅⾯(IP地址,⽤户代理等)来识别来⾃同⼀⼈的连续请求。实现状态保持的⽅式:在客户端或服务器端存储与会话有关的数据(客户端与服务器端的⼀次通信,就是⼀次会话)
cookies 是浏览器为 Web 服务器存的⼀⼩信息。 每次浏览器从某个服务器请求页面时,都会⾃动带上以前收到的cookie。cookie保存在客户端,安全性较差,注意不要保存敏感信息
HttpResponse.set_cookie(key, value='', max_age=None, expires=None, path='/', domain=None, secure=None, httponly=False)
# 同上,不同点在于设置salt,即加盐
HttpResponse.set_signed_cookie(key, value, salt='', max_age=None, expires=None, path='/', domain=None, secure=None, httponly=False)
key:cookie的名称(*)
value:cookie的值,默认是空字符
max_age:cookies的持续有效时间(以秒计),如果设置为None,cookies在浏览器关闭的时候就失效了。
expires:cookies的过期时间,格式:"Wdy,DD-Mth-YYHH:MM:SSGMT"如果设置这个参数,它将覆盖max_age。
path:cookie⽣效的路径前缀,浏览器只会把cookie回传给带有该路径的页面,这样你可以避免将cookie传给站点中的其他的应⽤。/表示根路径,根路径的cookie可以被任何url的⻚⾯访问
domain:cookie⽣效的站点。你可⽤这个参数来构造⼀个跨站cookie。如,domain=".example.com"所构造的cookie对下⾯这些站点都是可读的:www.example.com、www2.example.com。如果该参数设置为None,cookie只能由设置它的站点读取。
secure:如果设置为True,浏览器将通过HTTPS来回传cookie。
httponly:仅http传输不能使⽤js获取cookie
# 获取cookie
HttpRequest.COOKIES.get(key)
# 获取加“盐”的cookie
HttpRequest.get_signed_cookie(key, default=RAISE_ERROR, salt='',max_age=None)
# 删除cookie
HttpResponse.delete_cookie(key, path='/', domain=None)
app/views.py
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render, redirect
from django.urls import reverse
def check_login(func):
def inner(request, *args, **kwargs):
if request.COOKIES.get('username'):
return func(request, *args, **kwargs)
else:
return redirect(reverse('app:login'))
return inner
@check_login
def index(request):
return HttpResponse(request.COOKIES.get('username') + ' is login')
def login(request):
if request.method == 'POST':
postData = request.POST.dict()
postData.pop('csrfmiddlewaretoken')
# 这里我们为了方便不在进行数据库查询,直接设置username和password
if postData.get('username') == '123' and postData.get('password') == '123':
res = redirect(reverse('app:index'))
# 设置10s后过期
res.set_cookie(key='username', value=postData.get('username'), max_age=10)
return res
return render(request, 'app/login.html')
app/urls.py
from django.urls import path, include
from app import views
app_name = 'app'
urlpatterns = [
path('index/', views.index, name='index'),
path('login/', views.login, name='login'),
]
template/app/login.html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<form action="http://127.0.0.1:8000/app/login/" method="post">
{% csrf_token %}
username:<input type="text" name="username">
password:<input type="text" name="password">
<input type="submit">
</form>
</body>
</html>
我们运行项目可以发现,登陆以后我们可以到主界面,但是十秒钟以后刷新时就需要重新登陆了。
cookie看似解决了HTTP(短连接、⽆状态)的会话保持问题,但把全部⽤户数据保存在客户端,存在安全隐患,于是session出现了。我们可以把关于⽤户的数据保存在服务端,在客户端cookie⾥加⼀个sessionID(随机字符串)。其⼯作流程:
(1)、当⽤户来访问服务端时,服务端会⽣成⼀个随机字符串;
(2)、当⽤户登录成功后把{sessionID:随机字符串}组织成键值对加到cookie⾥发送给⽤户;
(3)、服务器以发送给客户端cookie中的随机字符串做键,⽤户信息做值,保存⽤户信息;
(4)、再访问服务时客户端会带上sessionid,服务器根据sessionid来确认⽤户是否访问过⽹站
这样我们的信息就保存在了服务器中,客户端只保存了SessionID,这样很安全,但是加重了服务器的负担,每次都需要查询服务器,而且分布式中这样的方式再不同的服务器上还需要重新登录。cookie在客户端存储值有⼤⼩的限制,⼤约⼏kb,session信息存储在服务器则没有限制
Session基于Cookies实现
# 这个app默认是有的
INSTALLED_APPS = [
'django.contrib.sessions',
]
# 这个中间件默认也是有的
MIDDLEWARE = [
'django.contrib.sessions.middleware.SessionMiddleware',
]
要使用Session必须先进行数据库的迁移
我们还用上一个例子来讲解Session的设置
只需要修改 views.py
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render, redirect
from django.urls import reverse
def check_login(func):
def inner(request, *args, **kwargs):
if request.session.get('username'):
return func(request, *args, **kwargs)
else:
return redirect(reverse('app:login'))
return inner
@check_login
def index(request):
return HttpResponse(request.session.get('username') + ' is login')
def login(request):
if request.method == 'POST':
postData = request.POST.dict()
postData.pop('csrfmiddlewaretoken')
# 这里我们为了方便不在进行数据库查询,直接设置username和password
if postData.get('username') == '123' and postData.get('password') == '123':
res = redirect(reverse('app:index'))
# 我们设置session,这里注意这个方法在request中
request.session['username'] = postData.get('username')
return res
return render(request, 'app/login.html')
我们监控我们提交表单的时候我们发送了什么,headers里面有Cookie
Cookie: csrftoken=SivHHihe4ppXF49toaZ0R2SxBisHyOpfwcU2cGi9K3B7JXdBIT71LAnMBHvinDFL; sessionid=epqs9x94bwy9pf8sf12d48bmg65f6s4l
我们发现我们发送了一个sessionID,至于我们保存的username已经被保存在了数据库中,这也是为什么要进行数据迁移的原因。
# clear 清空所有session,但不会把表中的数据删除
# flush 清空所有并删除表中数据
# logout 退出登录,清除所有并删除表中数据
# del req.session['key'] 删除某一个session值
def logout(request):
request.session.flush()
return redirect(reverse("App:login"))