【13.0】Django框架之Cookie和Session

【一】Cookie与Session的发展史详解

Cookie和Session是用来在Web应用程序中跟踪用户会话数据的两种常用技术。

【1】Cookie的发展史:

  1. 1994年,网景通信公司推出了第一个浏览器Cookie技术。Cookie是存储在用户计算机上的小型文本文件,用于跟踪用户在网站上的活动。
  2. 初始版本的Cookie只能存储很少的数据,并且没有强制加密机制,容易被恶意用户篡改或窃取。因此,随着互联网的快速发展,Cookie引起了一系列安全和隐私问题。

【2】Session的发展史:

  1. 由于Cookie存在的局限性,Web开发人员开始寻找更安全、可靠的替代方案。1997年,Sun Microsystems提出了基于服务器的会话管理方案,即Session。
  2. Session是在服务器端存储用户会话数据的一种技术。每当用户访问网站时,服务器会为其创建一个唯一的Session标识符(Session ID),并将会话数据存储在服务器上。
  3. Session ID一般通过Cookie或URL参数传递给客户端,用于识别用户的会话状态。

【3】Cookie和Session的关系:

  1. 在实际应用中,Cookie和Session通常结合使用。当用户首次访问网站时,服务器会为其分配一个唯一的Session ID,并将其存储在Cookie中,发送给客户端保存。
  2. 随后,客户端在每次请求中都会携带该Cookie,服务器通过解析Cookie中的Session ID,读取对应的会话数据,实现用户状态的跟踪和管理。

【4】总结:

  • Cookie和Session是Web应用程序中常用的用户会话跟踪技术。
  • Cookie通过在客户端存储小型文本文件,并将会话标识符传递给服务器,实现会话状态的保持。
  • 而Session则是在服务器端存储会话数据,通过Session ID实现对用户会话的追踪。
  • 它们的发展历程与互联网的发展紧密相关,为开发人员提供了更多的选择,以保障安全性和用户体验的提升。

【二】Cookie与Session详解

  • 1 网站都没有保存用户功能的需求,所有用户访问返回的结果都是一样的

    • 例如新闻、博客、文章...
  • 2 出现了一些需要保存用户信息的网站

    • 例如淘宝、支付宝、京东...
  • 以登录功能为例:
    • 如果不保存用户登录状态,也就意味着用户每次访问网站都需要重复的输入用户名和密码
    • 这对用户来说,体验感极差
  • 解决办法:
    • 当用户第一次登陆成功之后,将用户的用户名和密码返回给用户浏览器,让用户浏览器 保存在本地
    • 之后访问网站的时候浏览器自动将保存在本地的用户名和密码发送给服务端,服务端获取之后自动验证
    • 但是具有极大的安全隐患
  • 优化
    • 当用户登陆成功之后,服务端产生一个随机字符串(在服务端保存数据,用K:V键值对的形式),交由客户端浏览器保存
    • 之后访问服务端的时候,都带着随机字符串,服务端去数据库中比对是否有匹配到的随机字符串,从而获得用户信息
    • 但是如果截获到当前随机字符串,那么就可以冒充当前用户,其实还是有极大的安全隐患
  • 在web领域没有绝对的安全和绝对的不安全

【1】Cookie

  • 服务器保存在客户端浏览器上的信息都可以称之为cookie
  • 它的表现形式一般都是k:v键值对(可以有多个)

【2】Session

  • 保存在服务器上的信息都可以称之为session
  • 它的表现形式一般都是k:v键值对(可以有多个)

【3】token

  • session虽然数据是保存在服务端的,但是挡不住数据量大
  • 解决办法:服务端不再保存数据
    • 登陆成功之后,将一段信息加密处理(用自己独特的加密方式进行加密)
  • 将加密之后的结果拼接在信息后面,整体返回给浏览器保存
  • 浏览器下次访问的时候带着该信息,服务端自动切取前面的一段信息再次使用自己的加密算法进行加密
  • 然后用这段密文与携带过来的密文进行比对

【4】总结

  • cookie就是保存在客户端浏览器上的信息
  • session就是保存在服务端上的信息
  • session是基于cookie工作的(其实大部分的保存用户状态的操作都需要使用cookie)

【三】Django操作Cookie

  • 虽然cookie是服务端告诉客户端浏览器需要保存内容
  • 但是客户端浏览器可以选择拒绝保存
  • 如果禁止自动保存cookie
    • 那么只要是需要登录的网站都没办法正常登录了
  • 视图函数的返回值
return HttpResponse()
return render()
return redirect()
  • 变形
obj = HttpResponse()
return obj

obj1 = render()
return obj1

obj2 = redirect()
return obj2

如果想要操作cookie,必须进行以上变形才可以

【1】设置cookie

obj = HttpResponse()
obj.set_cookie(key,value)
return obj

【2】获取cookie

request.COOKIES.get(key)

【3】设置超时时间

obj = HttpResponse()
obj.set_cookie(key,value,max_age=5)
# 设置超时时间 5s 到期
return obj
  • max_age
    • 设置超时时间,以秒为单位
  • expiress
    • 设置超时时间 针对IE浏览器使用,以秒为单位

【4】注销cookie

obj = HttpResponse()
# 设置超时时间 5s 到期
obj.delete_cookie(key)
return obj
  • 注意
    • 这里只是拿 HttpResponse 举例,并不是这个参数只能是 HttpResponse
  • 比如
    • 我们想下一步跳转到某一个功能时,可以是
obj =  redirect('/home/')
obj.delete_cookie(key)
return obj

【登陆功能实现】

(1.0)简单实现

  • 路由
urlpatterns = [
    path('admin/', admin.site.urls),
    path('login/', views.login),
    path('home/', views.home),
]
  • 视图
def login(request):
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        if username == "dream" and password == "521":
            # 登陆成功之后,跳转到登陆成功之后才能看到的页面
            return redirect('/home/')
    return render(request, 'login.html')


def home(request):
    return HttpResponse("登陆成功!")
  • 前端
<form action="" method="post">
    <p>username:<input type="text" name="username" class="form-control"></p>
    <p>password:<input type="password" name="password" class="form-control"></p>
    <input type="submit" class="btn btn-success">
</form>
  • 问题
    • 登陆成功之后的跳转页面,不需要登陆也可以直接访问到,只需要给对应的地址即可

(2.0)解决登陆问题

from django.shortcuts import render, HttpResponse, redirect


# Create your views here.
def login(request):
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        if username == "dream" and password == "521":
            # 登陆成功之后,保存用户登陆状态
            obj = redirect('/home/')
            # 让浏览器记录cookie
            obj.set_cookie("sign", "1314521")
            '''
            浏览器不单单只是帮我们保存cookie
            而且在后面每次访问的时候都会带着cookie
            '''
            # 登陆成功之后,跳转到登陆成功之后才能看到的页面
            return obj
    return render(request, 'login.html')


def home(request):
    # 读取携带的cookie,cookie正确登陆成功
    if request.COOKIES.get("sign") == "1314521":
        return HttpResponse("登陆成功!")
    # 读取携带的cookie,cookie不正确跳转到登陆页面
    return redirect('/login/')

(3.0)迭代-登陆认证装饰器

  • 用户如果没有登陆的情况下想访问一个需要登录的页面
  • 那么先跳转到登录页面,当用户输入正确的用户名和密码之后
  • 再跳转到用户之前想访问的页面去,而不是直接写死
from django.shortcuts import render, HttpResponse, redirect


# Create your views here.
def login(request):
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        if username == "dream" and password == "521":
            # 获取用户上一次想要访问的url
            # 结果可能为空 -- 直接访问login
            tag_url = request.GET.get('tag_url')
            if tag_url:
                obj = redirect(tag_url)
            else:
                # 登陆成功之后,保存用户登陆状态
                obj = redirect('/home/')
            # 让浏览器记录cookie
            obj.set_cookie("sign", "1314521")
            '''
            浏览器不单单只是帮我们保存cookie
            而且在后面每次访问的时候都会带着cookie
            '''
            # 登陆成功之后,跳转到登陆成功之后才能看到的页面
            return obj
    return render(request, 'login.html')


# 校验用户登录状态的装饰器
def auth_check(func):
    def inner(request, *args, **kwargs):
        # 获取到用户上一次想要访问的url
        tag_url = request.get_full_path()
        # 读取携带的cookie,cookie正确登陆成功
        if request.COOKIES.get("sign") == "1314521":
            res = func(request, *args, **kwargs)
            return res
        else:
            # 读取携带的cookie,cookie不正确跳转到登陆页面
            return redirect(f'/login/?next={tag_url}')

    return inner


@auth_check
def home(request):
    return HttpResponse("home登陆成功!")


@auth_check
def index(request):
    return HttpResponse("index登陆成功!")


@auth_check
def func(request):
    return HttpResponse("func登陆成功!")

【四】Django操作Session

  • session数据是保存在服务端的,给客户端返回的是一个随机字符串
    • sessionid:随机字符串

【1】设置Session

request.session['key'] = value

【2】获取Session

request.session.get('key')

【3】设置/获取session多个值

  • 给session设置多个值的时候,存在数据库中的数据仍是一条
  • 但是在取session的时候,可以通过request.session对象获取到设置的多组键值对

【4】django_sessoin表中的session数据

  • django_sessoin表中的数据条数取决于浏览器
    • 同一个计算机(IP地址)上同一个浏览器只会有一条数据生效
    • 同一个计算机(IP地址)上多个浏览器会有多个数据生效
    • 当session过期的时候,可能会出现多条数据对应一个浏览器
      • 但是这些数据不会持久化存储,会被定时清理掉,可以手动清除也可以代码清除
  • 目的是为了节省服务器数据库资源

【5】设置过期时间

# 设置session
request.session['key'] = value
# 设置过期时间
request.session.set_expiry()
  • 参数
    • 整数
      • 多少秒过期
    • 日期对象
      • 到指定日期失效
    • 0
      • 一旦退出当前浏览器窗口就失效
    • 不写
      • 失效时间取决于Django内部全局session失效的时间

【6】清空session

(1)request.session.delete():

只删除服务端的

  • 该方法用于删除当前用户的Session数据,但会保留Session的Key。
  • 这意味着Session对象本身仍然存在,但其中的数据将被清空。
  • 下次访问时,如果Session没有被重新填充,则会得到一个空的Session对象。

以下是使用request.session.delete()的示例:

def clear_session(request):
    request.session.delete()
    # 其他操作或返回响应

(2)request.session.flush():

服务端和客户端都删除

  • 该方法用于完全删除当前用户的Session,包括Session对象和所有相关数据。
  • 下次访问时,将创建一个新的空Session对象。

以下是使用request.session.flush()的示例:

def clear_session(request):
    request.session.flush()
    # 其他操作或返回响应

【7】保存

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,默认修改之后才保存(默认)

【原理剖析】

  • *request*.session['sign'] = "369"内部发生了哪些事

    • Django内部会自动帮我们生成一个随机字符串

    • Django内部自动将随机字符串和对应的数据存储到 django_sessoin 表中

      • 先在内存中产生操作数据的内存

      • 在响应经过Django中间件的时候才去操作数据数据库

        'django.contrib.sessions.middleware.SessionMiddleware',
        
    • 将产生的随机字符串返回给客户端浏览器保存

  • request.session.get("sign")内部发生了哪些事

    • 自动从浏览器请求中获取 sessionid 对应的随机字符串
    • 根据该随机字符串去django_session表中查找对应的数据
      • 如果匹配成功,则将对应的数据取出并以字典的形式封装到request.session
      • 如果匹配不成功,则request.session中的数据为None

【案例演示】

(1.0)简单版

  • 路由
# session操作
path('set_session/', views.set_session),
  • 视图
def set_session(request):
    request.session['sign'] = "369"
    return HttpResponse("返回消息")
  • 会报错
OperationalError at /set_session/
no such table: django_session
  • 数据是保存在服务端的
    • 在默认情况下操作session的时候需要Django默认的一张 django_session
  • 数据库迁移命令时
    • Django会默认创建很多表,其中就有 django_session
  • Django默认session的过期时间是14天
    • 但是我们可以认为的修改过期时间

(2.0)解决办法

  • 先进行数据库迁移命令
    • 再进行访问
    • session 会自动保存到 django_session 表中

(3.0)优化

  • 路由
# session操作
path('set_session/', views.set_session),
path('get_session/', views.get_session),
  • 视图
def set_session(request):
    request.session['sign'] = "369"
    return HttpResponse("返回消息")


def get_session(request):
    request.session.get("sign")
    return HttpResponse("拿取成功消息")
posted @ 2023-07-17 17:27  Chimengmeng  阅读(28)  评论(0编辑  收藏  举报
/* */