Cookie
http 协议无状态的意思是每次请求都是独立的, 它的执行情况和结果与前面的请求和之后的请求都无直接关系, 它不会受前面的请求响应情况直接影响, 也不会直接影响后面的请求响应情况.
一句有意思的话来描述就是人生只如初见, 对服务器来说, 每次的请求都是全新的.
状态可以理解为客户端和服务器在某次会话中产生的数据, 那无状态的就以为这些数据不会被保留. 会话中产生的数据又是我们需要保存的, 也就是说要 "保持状态". 因此 Cookie 就是在这样一个场景下诞生.
它是服务器发送出来存储在浏览器上的一组组键值对, 下次访问服务器时浏览器会自动携带这些键值对, 以便服务器提取有用信息.
cookie 的工作原理是: 由服务器产生内容, 浏览器收到请求后保存在本地; 当浏览器再次访问时, 浏览器会自动带上 Cookie, 这样服务器就能通过 Cookie 的内容来判断这个是 "谁" 了
获取 Cookie
- request.COOKIES['key']
- request.get_signed_cookie(key, default=RAISE_ERROR, salt='', max_age=None)
参数:
default: 默认值
salt: 加密盐
max_age: 后台控制过期时间
设置 Cookie
- rep = HttpResponse(...)
- rep = render(request, ...)
- rep.set_cookie(key,value,...)
- rep.set_signed_cookie(key,value,salt='加密盐', max_age=None, ...)
参数:
key, 键
value='', 值
max_age=None, 超时时间
expires=None, 超时时间 (IE requires expires, so set it if hasn't been already.)
path='/', Cookie 生效的路径,/ 表示根路径, 特殊的: 根路径的 cookie 可以被任何 url 的页面访问
domain=None, Cookie 生效的域名
secure=False, https 传输
httponly=False 只能 http 协议传输, 无法被 JavaScript 获取 (不是绝对, 底层抓包可以获取到也可以被覆盖)
删除 Cookie
- def logout(request):
- rep = redirect("/login/")
- rep.delete_cookie("user") # 删除用户浏览器上之前设置的 usercookie 值
- return rep
Cookie 版登陆校验
- def check_login(func):
- @wraps(func)
- def inner(request, *args, **kwargs):
- next_url = request.get_full_path()
- if request.get_signed_cookie("login", salt="SSS", default=None) == "yes":
- # 已经登录的用户...
- return func(request, *args, **kwargs)
- else:
- # 没有登录的用户, 跳转刚到登录页面
- return redirect("/login/?next={}".format(next_url))
- return inner
- def login(request):
- if request.method == "POST":
- username = request.POST.get("username")
- passwd = request.POST.get("password")
- if username == "xxx" and passwd == "dashabi":
- next_url = request.GET.get("next")
- if next_url and next_url != "/logout/":
- response = redirect(next_url)
- else:
- response = redirect("/class_list/")
- response.set_signed_cookie("login", "yes", salt="SSS")
- return response
- return render(request, "login.html")
- Session
Cookie 虽然在一定程度上解决了 "保持状态" 的需求, 但是由于 Cookie 本身最大支持 4096 字节, 以及 Cookie 本身保存在客户端, 可能被拦截或窃取, 因此就需要有一种新的东西, 它能支持更多的字节, 并且他保存在服务器, 有较高的安全性. 这就是 Session.
问题来了, 基于 HTTP 协议的无状态特征, 服务器根本就不知道访问者是 "谁". 那么上述的 Cookie 就起到桥接的作用.
我们可以给每个客户端的 Cookie 分配一个唯一的 id, 这样用户在访问时, 通过 Cookie, 服务器就知道来的人是 "谁". 然后我们再根据不同的 Cookie 的 id, 在服务器上保存一段时间的私密资料, 如 "账号密码" 等等.
总结而言: Cookie 弥补了 HTTP 无状态的不足, 让服务器知道来的人是 "谁"; 但是 Cookie 以文本的形式保存在本地, 自身安全性较差; 所以我们就通过 Cookie 识别不同的用户, 对应的在 Session 里保存私密的信息以及超过 4096 字节的文本.
另外, 上述所说的 Cookie 和 Session 其实是共通性的东西, 不限于语言和框架.
Session 相关方法
- # 获取, 设置, 删除 Session 中数据 字典
- request.session['k1']
- request.session.get('k1',None)
- request.session['k1'] = 123
- request.session.setdefault('k1',123) # 存在则不设置
- del request.session['k1']
- # 所有 键, 值, 键值对
- request.session.keys()
- request.session.values()
- request.session.items()
- request.session.iterkeys()
- request.session.itervalues()
- request.session.iteritems()
- # 会话 session 的 key
- request.session.session_key
- # 将所有 Session 失效日期小于当前日期的数据删除
- request.session.clear_expired()
- # 检查会话 session 的 key 在数据库中是否存在
- request.session.exists("session_key")
- # 删除当前会话的所有 Session 数据
- request.session.delete()
- # 删除当前的会话数据并删除会话的 Cookie.
- request.session.flush()
这用于确保前面的会话数据不可以再次被用户的浏览器访问
例如, django.contrib.auth.logout() 函数中就会调用它.
- # 设置会话 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 == "user1" and pwd == "1234":
- # 设置 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})
来源: http://www.bubuko.com/infodetail-3095878.html