Django之cookie和session

在看Django官方文档的时候,找了半天都没看见有cookie的东西,不过session的倒是非常的详细。然后在博客园找了点关于Django中cookie的教程学习了下。😂

django

0x00 cookie

a_cookie的由来

最主要的原因就是HTTP协议是无状态的,而有些时候会话产生的数据信息有需要保留下来,比如在登录页面登录了,我们可以查看自己的个人信息,而个人信息的页面的访问,则需要“保持着”登录的状态才可以访问。

b_cookie的介绍

Cookie具体指的是一段小信息,它是服务器发送出来存储在浏览器上的一组组键值对,下次访问服务器时浏览器会自动携带这些键值对,以便服务器提取有用信息。

c_cookie的工作原理

cookie的工作原理主要是服务器上产生一个键值对,并随请求发送到浏览器端,保存在浏览器端;之后浏览器再次访问该网站的时候,则会带着这个键值对一起发送给服务端,服务端根据键值对的信息来判断数据。

d_cookie的查看方式

在Chrome或者Firefox中在页面按下F12,在Network中刷新页面,在点击相应的网页下就可以查看cookie了。

0x01 Django中cookie的操作

a_设置cookie

cookie与session略有区别,cookie是设置在“响应对象”上,而session是设置在“request”上。

rep = redirect("/app01/home/")
rep = render(request, "app01/homepage.html")

rep.set_cookie("is_login", "True")
rep.set_signed_cookie(key,value,salt='xzymoe', max_age=None, ...)

值得注意的是,在设置cookie的值的时候,建议设置为字符串类型,而不要用布尔类型或者整型。因为如果上面例子设置的为布尔型的True,而到时候获取通过request.Cookies.get()等方法获取到的cookie值时候,其已经是一个字符串型了,在进行比较的时候就容易成为类似”True” == True,而造成debug时候的问题。

cookie的参数

  • key:键
  • value:值
  • salt:加密盐
  • 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获取(不是绝对,底层抓包可以获取到也可以被覆盖)

b_cookie的获取

cookie的获取类似于键值对的获取,可以通过[‘键’]或者get(‘键’,默认值)的两种方式来获取。

# 普通cookie获取
request.COOKIES.['key']
request.COOKIES.get('key','0')

# 加密cookie获取
request.get_signed_cookie('key', default=PAISE_ERROR, salt='xzymoe',max_age=None)

c_cookie的删除

用户退出账户后,则需要对cookie进行删除。

def logout(request):
    rep = redirect("/app01/login/")
    rep.delete_cookie("is_login")
    return rep

0x02 cookie登录校验

大概功能就是,登录账户后才可以进入到home和index页面,如果直接访问home和index页面,则会返回到登录页面,登陆后则直接进入之前的页面。还有点小bug没改(比如用户在?path=后面直接乱输入参数则。。。)。

下面的代码使用了装饰器的方法,记住使用装饰器一定要使用functools。

from django.shortcuts import render, HttpResponse, redirect
from functools import wraps


# Create your views here.

def check_cookie(func):
    @wraps(func)
    def inner(request, *args, **kwargs):
        res = request.COOKIES.get("is_login", 0)  # 这个是字符串
        if res == "True":
            return func(request)
        else:
            return redirect("/app01/login/?path={}".format(request.path))

    return inner


def login(request):
    if request.method == "POST":
        username = request.POST.get("username", 0)
        password = request.POST.get("password", 0)

        path = request.GET.get("path", "0")

        if username == "chd" and password == "moe":
            if path == "0":
                rep = redirect("/app01/home/")
            else:
                rep = redirect(path)
            rep.set_cookie("is_login", True)  # 最好value设置为字符串,因为获取cookie得到的是字符串
            return rep
        else:
            return render(request, "app01/login.html")
    return render(request, "app01/login.html")

@check_cookie
def home(request):
    return render(request, "app01/homepage.html")


@check_cookie
def index(request):
    return render(request, "app01/index.html")


def logout(request):
    rep = redirect("/app01/login/")
    rep.delete_cookie("is_login")
    return rep

0x03 session

a_session的由来

虽然cookie的出现,可以保证了“保持状态”的需求,但是cookie也有一定的缺陷,首先cookie最大可以保存4096字节的内容,其次cookie其存储位置位于客户端的浏览器中,因而可能会被截取或者拦截,及时加密了,也可能被解密。因而了可以存储更多的数据以及更高的安全性,从而推出了session。

b_session的工作原理

其原理大概就是将之前的cookie存储到了服务器。而服务器在收到第一次登录请求后,随机生成一个字符串,字符串为“键”,而之前的cookie为“值”,“值”内包含了很多数据,被存储到了服务器。而将随机生成的字符串返回给浏览器。而这个字符串是随机的,对于窃取者来说并没有太多意义。

而访问服务端时候,这个随机字符串则被“以cookie的方式”发送到了服务端,服务端到数据库中匹配到了相应字符串对应的“值”,从而在服务端取到值。

0x04 Django中的session操作

Django中操作session是在request中操作,比cookie要方便很多哦~

Django在使用session时候需要使用到数据库,否则报错。配置好数据库后,使用migrate命令即可。在数据库表中则会自动生成一个django_session的表,用于存储session数据。

a_设置session

request.session['k1'] = 123
request.session.setdefault('k1',"123") # 存在则不设置

b_获取session

request.session.get("is_login", 0)  # 这个是字符串
request.session['is_login']

c_删除session

del request.session['is_login']

# 删除当前会话的所有Session数据
request.session.delete()

# 删除当前的会话数据并删除会话的Cookie。
request.session.flush() 

def logout(request):
    request.session.flush()
    return redirect("/app02/login/")

# 将所有Session失效日期小于当前日期的数据删除
request.session.clear_expired()

由于使用数据库的原因,当session失效后,依然保留数据库的行,因而可以通过最后一个方法来删除过期的session,以清理无用数据。

d_session的一些其他方法

# 所有 键、值、键值对
request.session.keys()
request.session.values()
request.session.items()
request.session.iterkeys()
request.session.itervalues()
request.session.iteritems()

# 会话session的key(用于判断当前session)
request.session.session_key

# 检查会话session的key在数据库中是否存在
request.session.exists("session_key")

# 设置会话Session和Cookie的超时时间
request.session.set_expiry(value)
    * 如果value是个整数,session会在些秒数后失效。
    * 如果value是个datatime或timedelta,session就会在这个时间后失效。
    * 如果value是0,用户关闭浏览器session就会失效。
    * 如果value是None,session会依赖全局session失效策略。

0x05 session的登录校验

和cookie的登录校验基本一直,只是改为了对session进行操作。

from django.shortcuts import render, HttpResponse, redirect
from functools import wraps


# Create your views here.

def check_session(func):
    @wraps(func)
    def inner(request, *args, **kwargs):
        res = request.session.get("is_login", 0)  # 这个是字符串
        if res == "True":
            return func(request)
        else:
            return redirect("/app02/login/?path={}".format(request.path))

    return inner


def login(request):
    if request.method == "POST":
        username = request.POST.get("username", 0)
        password = request.POST.get("password", 0)

        path = request.GET.get("path", "0")
        if username == "chd" and password == "qa":
            if path == "0":
                rep = redirect("/app02/home/")
            else:
                rep = redirect(path)
            request.session["is_login"] = "True"  # 最好value设置为字符串,因为获取cookie得到的是字符串
            return rep
        else:
            return render(request, "app02/login.html")
    return render(request, "app02/login.html")


@check_session
def home(request):
    return render(request, "app02/homepage.html")


@check_session
def index(request):
    return render(request, "app02/index.html")


def logout(request):
    request.session.flush()
    return redirect("/app02/login/")

发表评论