一、会话跟踪
客户端与服务器之间的一次会晤,在会晤中可能会包含多次请求和响应,客户向某一服务器发出第一个请求开始,会话就开始了,直到客户关闭了浏览器会话结束。在一个请求中共享数据,这就是会话跟踪技术。
HTTP协议是无状态协议,他的每个请求都是独立的,无法记录前一次请求的状态,但是HTTP协议中可以使用Cookie技术来完成会话跟踪,在web开发中,使用session来完成会话跟踪,session底层依赖cookie技术。
二、cookie
1、cookie概述
cookie是浏览器技术,cookie具体指的是一段小信息,由服务器发送的存储在浏览器上的一组组键值对,浏览器下次发哦是那个请求时会携带这些信息。
查看cookie:
2、cookie规范
HTTP的cookie规范:
-
Cookie大小上限为4kb
-
一个服务器最多在客户端浏览器上保存20个cookie
-
一个浏览器最多保存300个cookie
现在的不同的浏览器的cookie规范可能不同,而且不同的浏览器之间的cookie不能共享。浏览器的cookie是会覆盖的,服务端重复发送的Cookie会覆盖原来的cookie。
三、django中操作cookie
1、设置cookie
rep = HttpResponse(...)# rep = render(request, ...)或rep = redirect(request, ...)
rep.set_cookie(key, value)
rep.set_signed_cookie(key_value,salt=\'加密盐\',...)
2、获取cookie
request.COOKIES实际上是字典,封装了这次请求的cookie键值
request.COOKIES.get(\'key\')
# 或request.COOKIES[key]
request.get_signed_cookie(key, default=RAISE_ERROR, salt=\'\', max_age=None)
参数:
- default:默认值
- salt:加密盐
- max_age:超时时间
3、删除cookie
响应体.delete_cookie(\'键值\')
rep = rediect("login")
rep.delete_cookie("user") # 删除用户浏览器上之前设置的usercookie值
在浏览器中清除页面缓存和cookie:Ctrl + Shift + del
4、cookie版的登录校验
5、set_cookie参数介绍
def set_cookie(self, key, value=\'\', max_age=None, expires=None, path=\'/\',
domain=None, secure=False, httponly=False):
-
param self:
-
param key: 键
-
param value: 值
-
param max_age: 超长时间cookie需要延续的时间(以秒为单位)如果参数是None ,
``这个cookie会延续到浏览器关闭为止。 -
param expires: 超长时间expires默认None ,cookie失效的实际日期/时间。
-
param path: Cookie生效的路径,浏览器只会把cookie回传给带有该路径的页面,这样可以避免将cookie传给站点中的其他的应用。
-
/ 表示根路径,特殊的:根路径的cookie可以被任何url的页面访问
-
param domain: Cookie生效的域名你可用这个参数来构造一个跨站cookie。
如, domain=".example.com"所构造的cookie对下面这些站点都是可读的:www.example.com www2.example.com 和an.other.sub.domain.example.com 。
如果该参数设置为 None ,cookie只能由设置它的站点读取。 -
param secure: 如果设置为 True ,浏览器将通过HTTPS来回传cookie。
-
param httponly: 设置为False,只能http协议传输,无法被JavaScript获取(不是绝对,底层抓包可以获取到也可以被覆盖)
1)max_age
未设置则cookie持续到浏览时关闭,max_age = 10,表示cookie在10秒内有效
2)expries
在指定的日期失效,使用时需要引入datetime模块
import datetime
date = datetime.datetime(year=2018, month=5, day=29, hour=10, minute=20, second=11)
response.set_cookie(\'username\',user.user,expries=date)
3)path
针对哪些路径下的视图可以取到cookie
response.set_cookie(\'username\', user.user, path=\'/index/\')
显示上次登陆时间
<h3>HI,{{ username }}</h3>
<p>上次登录时间: {{ last_time }}</p>
def index(request):
# 取到Cookie
print("index", request.COOKIES) # request.COOKIES实际是一个字典,封装了这次请求封装的所有cookie键值
is_login = request.COOKIES.get("is_login")
if is_login:
# 取到值,登录成功
username = request.COOKIES.get("username")
# 上一次访问时间,其实就是上一次访问index的时间:
import datetime
now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
last_time = request.COOKIES.get("last_visit_time", "") # 每次登录取上一次登录时间,取不到默认为空
response = render(request, "index.html", {"username": username, "last_time": last_time})
response.set_cookie("last_visit_time", now)
return response
else:
# 取不到值,跳转到登录页面
return redirect("/login/")
四、session
cookie在一定程度上解决了“保持状态”的需求,但是cookie是存储在客户端的可能被拦截或者篡改,因此需要支持更多字节并保存在服务器上的,有较高的安全性,所以诞生了Session这种服务端的技术,服务器可以为每个浏览器创建一个其独享的session对象,所以用户在访问服务器时,可以把各自的数据放在各自的session中,当用户再去访问该服务器的其他web资源时,其他web资源再从用户各自的session中取出数据为用户服务。
- 生成随机字符串
- 服务器给浏览器的响应体里设置set_cookie,键为sessionid,值为对应的随机字符串
- 再django—session表中生成一条记录,session-key为随机字符串,session-data是设置的session值[\'username\']=\'an\'
- 浏览器再一次发送请求到某一视图函数中,这个函数如果要取session:request.session[‘username’]即可。1)读cookie里的sessionid对应的随机字符串;(2)在django-session表中过滤session-key等于随机字符串的记录。(3)在过滤出的记录对象中取出session-data对应的字典,再.get("username")可以把对应的“an”取出。
五、django操作session
1、基本操作
注意:这都是django提供的方法,其他的框架就需要你自己关于cookie和session的方法了。
获取、设置、删除Session中数据
# setting.py
# 可以修改sessionid名称
SESSION_COOKIE_NAME = \'sessionid\'
1)取值
request.session[\'k1\']
request.session.get(\'k1\',None) #request.session
这句是帮你从cookie里面将sessionid的值取出来,将django-session表里面的对应sessionid的值的那条记录中的session-data字段的数据给你拿出来(并解密),get方法就取出k1这个键对应的值
2)设置值
request.session[\'k1\'] = 123
request.session.setdefault(\'k1\',123)
存在则不设置#帮你生成随机字符串,帮你将这个随机字符串和用户数据(加密后)和过期时间保存到了django-session表里面,帮你将这个随机字符串以sessionid:随机字符串的形式添加到cookie里面返回给浏览器,这个sessionid名字是可以改的,以后再说#但是注意一个事情,django-session这个表,你不能通过orm来直接控制,因为你的models.py里面没有这个对应关系#删除值
del request.session[\'k1\'] #django-session表里面同步删除
3)所有 键、值、键值对
request.session.keys()
request.session.values()
request.session.items()
4)会话session的key
session_key = request.session.session_key # 获取sessionid的值
将所有Session失效日期小于当前日期的数据删除,将过期的删除
request.session.clear_expired()
5)检查会话session的key在数据库中是否存在
request.session.exists("session_key") #session_key就是那个sessionid的值
6)删除当前会话的所有Session数据
request.session.delete()
7)删除当前的会话数据并删除会话的Cookie。
request.session.flush()
常用,清空所有cookie---删除session表里的这个会话的记录,这用于确保前面的会话数据不可以再次被用户的浏览器访问,例如,django.contrib.auth.logout() 函数中就会调用它。
8)设置会话Session和Cookie的超时时间
request.session.set_expiry(value)
- 如果value是个整数,session会在些秒数后失效。
- 如果value是个datatime或timedelta,session就会在这个时间后失效。
- 如果value是0,用户关闭浏览器session就会失效。
- 如果value是None,session会依赖全局session失效策略。
session版的登陆验证示例:
from functools import wraps
def check_login(func):
@wraps(func)
def inner(request, *args, **kwargs):
next_url = request.get_full_path()
if request.session.get("user"):
return func(request, *args, **kwargs)
else:
return redirect("/login/?next={}".format(next_url))
return inner
def login(request):
if request.method == "POST":
user = request.POST.get("user")
pwd = request.POST.get("pwd")
if user == "alex" and pwd == "alex1234":
# 设置session
request.session["user"] = user
# 获取跳到登陆页面之前的URL
next_url = request.GET.get("next")
# 如果有,就跳转回登陆之前的URL
if next_url:
return redirect(next_url)
# 否则默认跳转到index页面
else:
return redirect("/index/")
return render(request, "login.html")
@check_login
def logout(request):
# 删除所有当前请求相关的session
request.session.delete()
return redirect("/login/")
@check_login
def index(request):
current_user = request.session.get("user", None)
return render(request, "index.html", {"user": current_user})
2、session配置
1. 数据库Session
SESSION_ENGINE = \'django.contrib.sessions.backends.db\' # 引擎(默认)
2. 缓存Session
SESSION_ENGINE = \'django.contrib.sessions.backends.cache\' # 引擎
SESSION_CACHE_ALIAS = \'default\' # 使用的缓存别名(默认内存缓存,也可以是memcache),此处别名依赖缓存的设置
3. 文件Session
SESSION_ENGINE = \'django.contrib.sessions.backends.file\' # 引擎
SESSION_FILE_PATH = None # 缓存文件路径,如果为None,则使用tempfile模块获取一个临时地址tempfile.gettempdir()
4. 缓存+数据库
SESSION_ENGINE = \'django.contrib.sessions.backends.cached_db\' # 引擎
5. 加密Cookie Session
SESSION_ENGINE = \'django.contrib.sessions.backends.signed_cookies\' # 引擎
其他公用设置项:
SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串(默认)
SESSION_COOKIE_PATH = "/" # Session的cookie保存的路径(默认)
SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名(默认)
SESSION_COOKIE_SECURE = False # 是否Https传输cookie(默认)
SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http传输(默认)
SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周)(默认)
SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否关闭浏览器使得Session过期(默认)
SESSION_SAVE_EVERY_REQUEST = False # 是否每次请求都保存Session,默认修改之后才保存(默认)
2、补充
csrf_protect,为当前函数强制设置防跨站请求伪造功能,即便settings中没有设置全局中间件。强制保护。
csrf_exempt,取消当前函数防跨站请求伪造功能,即便settings中设置了全局中间件。强制保护。
from django.views.decorators.csrf import csrf_exempt, csrf_protect
# 表单中可以不写{{ csrf_token }}
@csrf_exempt
def func2(request):
pass