Django之cookie与session

Django 之 Cookie 与 Session

  Cookie 和 Session 是为了在无状态的HTTP协议之上维护会话状态,使得服务器可以知道当前是和哪个客户在打交道。

  因为 HTTP 协议是无状态的,即每次用户请求到达服务器时,HTTP 服务器并不知道这个用户是谁、是否登录过等。现在的服务器之所以知道我们是否已经登录,是因为服务器在登录时设置了浏览器的 Cookie!Session 则是借由 Cookie 而实现的更高层的服务器与浏览器之间的会话。

 

Cookie

概念

  Cookie 是由客户端保存的小型文本文件,其内容为一系列的键值对。 Cookie 是由 HTTP 服务器设置的,保存在浏览器中, 在用户访问其他页面时,会在 HTTP 请求中附上该服务器之前设置的 Cookie。

传递流程

  1. 浏览器向某个 URL 发起 HTTP 请求(可以是任何请求,比如 GET 一个页面、POST 一个登录表单等)
  2. 对应的服务器收到该 HTTP 请求,并计算应当返回给浏览器的 HTTP 响应。
  3. 在响应头加入 set-cookie 字段,它的值是要设置的 Cookie。
    UserAgent(浏览器就是一种用户代理)至少应支持 300 项 Cookie, 每项至少应支持到 4096 字节,每个域名至少支持 20 项 Cookie
  4. 浏览器收到来自服务器的 HTTP 响应。
  5. 浏览器在响应头中发现 set-cookie 字段,就会将该字段的值保存在内存或者硬盘中。
    set-cookie 字段的值可以是很多项 Cookie,每一项都可以指定过期时间 Expires默认的过期时间是用户关闭浏览器时。
  6. 浏览器下次给该服务器发送 HTTP 请求时, 会将服务器设置的 Cookie 附加在 HTTP 请求的头字段 Cookie 中。
    浏览器可以存储多个域名下的 Cookie,但只发送当前请求的域名曾经指定的 Cookie, 这个域名也可以在 set-cookie 字段中指定。
  7. 服务器收到这个 HTTP 请求,发现请求头中有 Cookie 字段, 便知道之前就和这个用户打过交道了。
  8. 过期的 Cookie 会被浏览器删除。

  服务器通过 set-cookie 响应头字段来指示浏览器保存 Cookie, 浏览器通过 Cookie 请求头字段来告诉服务器之前的状态。 Cookie 中包含若干个键值对,每个键值对可以设置过期时间。  

作用

  HTTP 协议是无状态的,每次请求都是无关联的,没有办法保存状态,所以使用 Cookie 保存状态。

特性

  服务器让浏览器保存的 Cookie。

  浏览器有权拒绝保存 Cookie,但是当浏览器拒绝保存 Cookie 时,就无法完成 Web 登录。

应用

  web 登录、习惯记录、投票等。

缺点

  Cookie 长度有限,能保存的数据量有限。

  Cookie 保存在本地,导致数据不安全。

使用

  由于 Cookie 以字典的形式保存,所以使用操作字典的方式来操作 Cookie。

设置 Cookie

  普通设置,key 为键,value 为值,max_age 为后台控制过期时间。

ret = HttpResponse('xxoo')
ret.set_cookie(key, value, max_age=5)

设置加密 Cookie

  salt 为设置加密用的盐。

ret = HttpResponse('xxoo')
ret.set_signed_cookie(key, max_age=5, salt='xxoo')

  Cookie 可以设置多个参数,具体参数关键字如下:

key
value=''
max_age=None 超时时间
ecpires=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

  获取普通方式设置的 Cookie

    方法一:

request.COOKIES['is_login']  # 假设 is_login 为之前设置的 key

    方法二:

request.COOKIES.get('is_login')  # 假设 is_login 为之前设置的 key

  获取加盐设置的 Cookie

request.get_signed_cookie(key, salt='xxoo', default='')

  其中 default 为默认值。

删除 cookie

ret.delete_cookie(key)  # key 为之前设置的键

Django 框架中的使用示例之 Cookie 版登录

from django.shortcuts import render, redirect
from django.views import View

# Create your views here.
def login_required(fn):
    """
    装饰器,在登陆之前验证 Cookie
    """

    def inner(request, *args, **kwargs):

        if request.COOKIES.get('is_login') != '1':  # 判断 Cookie 的值是否为之前设定的值
            next = request.path_info  # 获取 url 端口号之后的其他路径信息

            return redirect(f'/login/?next={next}')  # 将获取到的路径信息拼接到login之后跳转到login路由

        ret = fn(request, *args, **kwargs)

        return ret

    return inner


class Login(View):

    def get(self, request):

        return render(request, 'login.html')

    def post(self, request):
        user = request.POST.get('user')  # 获取用户填写的用户名
        pwd = request.POST.get('pwd')  # 获取用户填写的密码

        if user == 'a' and pwd == '1':  # 判断用户名与密码的正确性
            next = request.GET.get('next')  # 获取login后面拼接的路径信息
            if next:  # 判断是否有拼接路径
                ret = redirect(next)  # 跳转到拼接的路径路由上
            else:
                ret = redirect('/index/')  # 跳转到index路由上
            ret.ret_cookie['is_login'] = '1'  # 设置Cookie的值

            return ret

        else:

            return redirect('/login/')  # 登录失败跳转到登录页面重新登录


@login_required
def index(request):

    return  render(request, 'index.html')


@login_required
def home(request):

    return render(request, 'home.html')


def logout(request):
    ret = redirect('/login/')
    request.delete_cookie('is_login')  # 注销删除Cookie

    return ret

Session

概念

   保存在服务器上的一组组键值对,与Cookie搭配使用。

作用

  Cookie保存在浏览器本地,容易非法获取,不安全;而session是保存在服务器上,数据安全。

  Cookie的长度受到限制,而session是经过加密换算得到的结果,不受长度限制。

Django中的使用

设置Session

  方法一:

request.session[key] = value

  方法二:

request.session.setdefault(key, value)

获取Session

  方法一:

request.session[key]

  方法二:

request.session.get(key)

删除Session

  删除某一个(指定)键值对

del request.session[key]

  删除该用户的所有的Session数据,不删除Cookie

request.session.delete()

  删除该用户的所有的Session数据,删除Cookie

request.session.flush

设置超时时间

request.session.set_expiry()

清除所有过期的Session

request.session.clear_expired()

配置

Session的表名

# Cookie name. This can be whatever you want.
SESSION_COOKIE_NAME = 'sessionid'  # 默认的表名为sessionid

超时时间

# Age of cookie, in seconds (default: 2 weeks).
SESSION_COOKIE_AGE = 60 * 60 * 24 * 7 * 2  # 默认超时时间为两周

每次都改变Session的值   # 是否在每个请求中保存会话数据。

# Whether to save the session data on every request.
SESSION_SAVE_EVERY_REQUEST = False

当Web浏览器关闭时,用户的会话Cookie是否过期。

# Whether a user's session cookie expires when the Web browser is closed.
SESSION_EXPIRE_AT_BROWSER_CLOSE = False

设置数据库引擎

SESSION_ENGINE = 'django.contrib.sessions.backends.db'

注意

  使用Session时,app文件夹和中间件中都要有Session的配置参数。

  服务器只认浏览器,不认用户,当用户发生改变时,或覆盖之前的值,key不变。

  同一个浏览器(本地),登录同一个账号,服务器中存储的内容不变。

  关闭浏览器失效的是本地浏览器中的cookie。

Django框架中的使用示例之Session登录

from django.shortcuts import render, redirect
from django.views import View

# Create your views here.
def login_required(fn):
    """
    装饰器,在登陆之前验证session
    """

    def inner(request, *args, **kwargs):

        if request.session.get('is_login') != '1':  # 判断session的值是否为之前设定的值
            next = request.path_info  # 获取url端口号之后的其他路径信息

            return redirect(f'/login/?next={next}')  # 将获取到的路径信息拼接到login之后跳转到login路由

        ret = fn(request, *args, **kwargs)

        return ret

    return inner


class Login(View):

    def get(self, request):

        return render(request, 'login.html')

    def post(self, request):
        user = request.POST.get('user')  # 获取用户填写的用户名
        pwd = request.POST.get('pwd')  # 获取用户填写的密码

        if user == 'a' and pwd == '1':  # 判断用户名与密码的正确性
            next = request.GET.get('next')  # 获取login后面拼接的路径信息
            if next:  # 判断是否有拼接路径
                ret = redirect(next)  # 跳转到拼接的路径路由上
            else:
                ret = redirect('/index/')  # 跳转到index路由上
            ret.session['is_login'] = '1'  # 设置session的值

            return ret

        else:

            return redirect('/login/')  # 登录失败跳转到登录页面重新登录


@login_required
def index(request):

    return  render(request, 'index.html')


@login_required
def home(request):

    return render(request, 'home.html')


def logout(request):
    ret = redirect('/login/')
    request.session.flush()  # 注销删除session信息和cookie值

    return ret

 

参考文章

Cookie/Session的机制与安全

 

posted @ 2018-10-15 17:29  AKA绒滑服贵  阅读(155)  评论(0编辑  收藏  举报