Django框架学习笔记—会话技术(Cookie、Session、Token)

概述

理论上,一个用户的所有请求操作都应该属于同一个会话,而另一个用户的所有请求操作则应该属于另一个会话,二者不能混淆。而Web应用程序是使用HTTP协议传输数据的,HTTP协议是无状态的协议,一旦数据交换完毕,客户端与服务器端的连接就会关闭,再次交换数据需要建立新的连接。这就意味着服务器无法从连接上跟踪会话,无法从网络连接知道客户身份,那怎么办呢?

那就给每个客户端颁发一个通行证,每人一个,无论谁访问都必须携带自己通行证,这样服务器就能从通行证上确认客户身份了

Cookie
原理

Cookie就是这样一种机制,是一种客户端会话技术

Cookie实际上是一小段的文本信息,客户端请求服务器,如果服务器需要记录该用户状态,就使用response向客户端浏览器颁发一个Cookie,客户端浏览器会把Cookie保存起来,当浏览器再请求该网站时,浏览器把请求的网址连同该Cookie一同提交给服务器,服务器检查该Cookie,以此来辨认用户状态。服务器还可以根据需要修改Cookie的内容

cookie本身由服务器生成,以key-value的形式进行存储,通过Response将cookie写到浏览器上,下一次访问,浏览器会根据不同的规则携带cookie过来

注意:cookie不能跨浏览器,一般不跨域

设置cookie

在views.py中添加login视图函数,如下

from django.http import HttpResponse
from django.shortcuts import render
from App.models import User

def login(request):
    if request.method == 'GET':
        return render(request,'login.html')
    elif request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        users = User.objects.filter(username=username,password=password)
        if users.exists():
            res = HttpResponse('登录成功!')
            res.set_cookie('userid',users.first().id)
            return res
        else:
            return render(request,'login.html')

使用response.set_cookie()进行设置cookie

response.set_cookie(key,value[,max_age=None,expires=None])

max_age: 整数, 单位为秒, 指定cookie过期时间, 默认为None, 表示浏览器关闭失效

expires: 指定过期时间, 还支持datetime或timedelta, 可以指定一个具体日期时间

例如:

# 第一种方法
expires = datetime.datetime(2019, 1, 1, 2, 3, 4)
# 第二种方法
expires = datetime.datetime.now() + datetime.timedelta(days=1) # 1天后失效

注意:max_age和expries两个选一个指定

login.html代码如下:

<body>
    <h2>登录</h2>
    <hr>
    <form action="{% url 'login' %}" method="post">
        {% csrf_token %}
        <p>用户名:<input type="text" name="username"></p>
        <p>密码:<input type="password" name="password"></p>
        <p><input type="submit" value="登录"></p>
    </form>
</body>

csrf:跨站伪造请求

解决csrf在post请求时产生的403错误:

  1. 注释settings.py中MIDDLEWARE的csrf相关中间件

  2. 在form表单中添加{% csrf_token %}

获取cookie

有一些功能需要用户登录后才能访问,比如购物车,这时就可以获取cookie,验证用户是否登录,代码如下:

def cart(request):
    userid = request.COOKIES.get('userid')
    user = User.objects.filter(id=userid).first()
    if user:
        return HttpResponse('购物车')
    else:
        return HttpResponse('请先登录')

使用request.COOKIES.get(key)获取cookie

删除cookie

当用户退出登录时,要删除cookie,代码如下:

def logout(request):
    res = HttpResponse('注销')
    res.delete_cookie('userid')
    return res

使用response.delete_cookie(key)来删除cookie

cookie小结
  1. 浏览器的会话技术,cookie存储在客户端
  2. cookie一般不跨域,不能跨浏览器
  3. cookie一般是小于4KB的文本
  4. cookie是由服务器端设置,cookie内容一般和当前用户相关
  5. 优点:数据存在在客户端,减轻服务器端的压力,提高网站的性能
  6. 缺点:安全性不高,在客户端机很容易被查看或破解用户会话信息
Session

session是一种服务器端会话技术,依赖于cookie

session数据存储在数据库django_session表中,并且做了基本的数据安全处理(base64编码),如下图:
在这里插入图片描述
将Session在数据库中的session_key,当作sessionid,存储在cookie中,session_data则为用户信息

配置

zaidjango中启用session,需要在settings.py文件中配置,如下:

INSTALLED_APPS = [
	'django.contrib.sessions'
]

MIDDLEWARE = [
	'django.contrib.sessions.middleware.SessionMiddleware'
]				

一般创建应用时,会自动添加,无需手动添加

设置session
request.session['userid'] = users.first().id
request.session.set_expiry(60*60*24)	# 秒, 设置过期时间

每个HttpRequest对象都有一个session属性,也是一个类字典对象

获取session
# 第一种方法
userid = request.session.get('userid')
# 第二种方法
userid = request.session['userid']	# key不存在时报错
删除session
# 第一种方法
session_key = request.session.session_key	# 获取当前请求的session的key
request.session.delete(session_key)
# 第二种方法
request.session.delete('userid')
# 第三种方法
del request.session['userid']	# key不存在时报错
clear和flush

session是有一级缓存的,目的是为了减少查询数据库的时间,提高效率,一级缓存的生命周期和session是一样的

session.flush()和session.clear()就针对session的一级缓存的处理

简单的说:

  1. session.flush():删除当前的会话数据并删除会话的cookie,将session的缓存中的数据与数据库同步
  2. session.clear():清除所有会话,清除session中的缓存数据(不管缓存与数据库的同步)
session小结
  1. 服务端的会话技术,session数据保存在服务端
  2. 优点:安全
  3. 缺点:对服务器有一定的压力
  4. 注意:使用ajax跨域请求时,跨域的时候所创建的session是不会被浏览器保存下来的。所以每次进行跨域请求时,服务器都认为不是同一个浏览器所发起的请求,session也会不一样
Token

Token是一种服务端会话技术,相当于手动实现的session,主要用在移动端,通过特定算法得到唯一的Token值

生成数据表

使用UserToken表保存token值

class User(models.Model):
    username = models.CharField(max_length=10)
    password = models.CharField(max_length=32)

class UserToken(models.Model):
    token = models.CharField(max_length=100, unique=True, null=False, verbose_name='用户令牌/用户的唯一标识')
    user = models.OneToOneField(User, on_delete=models.PROTECT ,verbose_name='关联的用户')
    out_time = models.DateTimeField(null=False, verbose_name='过期时间')
设置token
import datetime
import uuid
from django.http import HttpResponse
from django.shortcuts import render
from App.models import User, UserToken

def login(request):
    if request.method == 'GET':
        return render(request,'login.html')
    elif request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        users = User.objects.filter(username=username,password=password)
        if users.exists():
            res = HttpResponse('登录成功!')
            # 创建一个唯一的token值
            token = uuid.uuid4().hex
            # 设置过期时间
            out_time = datetime.datetime.utcnow() + datetime.timedelta(days=1)
            u_token = UserToken.objects.filter(user__id=users.first().id).first()
            if u_token:
            	# 如果当前登录的用户已经存在对应的token记录,则修改token记录即可
                u_token.token = token
                u_token.out_time = out_time
                u_token.save()
            else:
            	# 如果第一次登录,创建token
                user_token = UserToken()
                user_token.token = token
                user_token.user = users.first()
                user_token.out_time = out_time
                user_token.save()
            # 借助cookie将token存入浏览器端
            res.set_cookie('token', token, max_age=60*60*24)
            return res
        else:
            return render(request,'login.html')
获取token
def cart(request):
    token = request.COOKIES.get('token')
    user_token = UserToken.objects.filter(token=token).first()
    # 判断token是否存在
    if user_token:
        print(user_token.out_time)
        print(datetime.datetime.utcnow())
        # 判断token是否过期
        if user_token.out_time.timestamp() > datetime.datetime.utcnow().timestamp():
            return HttpResponse('购物车')
    return HttpResponse('请先登录')
删除token
def logout(request):
    res = HttpResponse('注销')
    # 删除cookie中的token
    res.delete_cookie('token')
    # 删除usertoken表中的记录
    token = request.COOKIES.get('token')
    UserToken.objects.filter(token=token).delete()
    return res
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值