16 django之Cookie、Session、Token

611次阅读
没有评论

共计 8308 个字符,预计需要花费 21 分钟才能阅读完成。

一.Cookie、Session、Token 的由来

我们知道 HTTP 协议无连接 的, 也就是不保存用户的状态信息

早期 (十几年前) 的网页是静态的, 数据都是写死的, 人们访问网页只是用来查看新闻的, 没有保存用户状态的需求

而往后出现了像论坛、博客、网购这一类需要保存用户信息的网站, 如果网站不保存用户的状态信息, 意味着用户每次访问都需要重新输入用户名和密码, 这无疑对用户的体验是极其不好的

于是, 就出现了 会话跟踪技术, 我们可以把它理解为客户端与服务端之间的一次会晤, 一次会晤包含的多次请求与响应, 每次请求都带着请求参数, 比如请求登入的请求参数是用户名和密码, 服务端就会拿着请求参数与数据库去比对, 找到相应的用户信息

如何实现会话跟踪 : 在 HTTP 协议中可以使用 Cookie 来完成, 在 Web 开发中可以使用 Session 来完成

  • Cookie 是存在浏览器中的键值对, 每次发送请求都携带者参数, 但是容易被截获, 不安全

  • 于是就出现了 Session, 它是存在于服务端的键值对, key 为随机字符串, 安全性提高了, 但所有的数据都存在服务器中, 服务器的压力很大

  • 之后便产生了 Token 的概念, 服务端签发加密后的字符串给客户端浏览器保存, 客户端每次请求携带用户名和密码, 并加上由服务端签发的用户名和密码加密的字符串, 服务端收到请求后再对用户名密码加密, 与后面携带的密文对比, 由于它也是保存在客户端浏览器上的, 所以也叫 Cookie

二.Cookie 简介

1. 什么是 Cookie

  • Cookie 是服务器保存在客户端浏览器之上的 key-value 键值对 : username='shawn';password="123"
  • 它是随着服务器的响应发送给客户端, 客户端将其保存, 下一次请求时会将 Cookie 放在其中, 服务器通过识别 Cookie 就能知道是哪个客户端浏览器

2.Cookie 规范

  • Cookie 大小上限为 4KB
  • 一个服务器最多在客户端浏览器上保存 20 个 Cookie
  • 一个浏览器最多保存 300 个 Cookie

上面是 HTTP 中 Cookie 的规范, 现在浏览器的竞争, 有些 Cookie 大小能打到 8KB, 最多可以保存 500 个 Cookie

不同浏览器之间的 Cookie 是不共享的

3. 安全性

  • Cookie 保存在浏览器本地, 意味着很容易被窃取和篡改

三.Session 简介

1. 什么是 Session

  • 存放在服务器上的键值对 : {'weqweq':{'username':'shawn','password':'123'}}

  • Cookie 可以保存状态, 但本身最大只能支持 4069 字节, 并且不安全, 于是就出现了 Session

  • 它能支持更多字节, 并且保存在服务器上, 具有较高的安全性,Session 基于 Cookie, 本地存放服务器返回给浏览器的随机字符串
  • 客户端浏览器请求中携带随机字符串(session_id), 服务端收到后与数据库中存储的 session 做对比

ps : session 存储的方式多种多样, 可以是数据库、缓存、硬盘等等

2.Cookie、Session 小结

1. cookie 是存在于浏览器上的, 保存形式以 key:value 键值对的形式
2. session 是存在于服务端的, django 中保存在 django_session 表中, key: 对应 session_key 字段, value: 对应 session_data, 还有一个 session_date 用来保存终止会话时间
3. session 是基于 cookie 工作的, 在 django 中 session 会告知浏览器以 sessionid: 随机字符的格式保存数据

四.Token 简介

1. 什么是 Token

  • session 数据保存在服务端, 提升了安全性, 但如果用户数据量特别多, 那么服务器的压力就会非常大
  • 所以不再在服务端中保存数据
  • Token 采用了 jwt(json web token) 的认证方式, 数据格式分为 三段式 : {公司信息。。}.{name:lqz,id:10}. 加密后的字符串
  • 登入成功之后, 将第一段数据与第二段数据进行加密(加密算法是你后端开发自定义的), 加密后得到的字符串放在最后一段, 然后整体的返回给浏览器
  • 浏览器下次访问的时候就会带着该信息, 服务端收到再取前两段进行加密与第三段对比

五.django 中 cookie 的使用

1.Cookie 四件套

  • 增 : obj.set_cookie('key','value)
  • 查 : request.COOKIE.get('key')
  • 改 : obj.set_cookie('key','value')
  • 删 : obj.delete_cookie('key')

2.Cookie 四件套示例

def cookie_test(request):
    # obj1 = HttpResponse()
    # return obj1
    # obj2 = render(request,'cookie_test.html')
    # return obj2

    obj = HttpResponse('生成了两个 cookie')

    # 设置 cookie
    obj.set_cookie('name','shawn')
    obj.set_cookie('pwd','123')

    return obj

16 django 之 Cookie、Session、Token

16 django 之 Cookie、Session、Token

# 获取 cookie
def get_cookie(request):
    name = request.COOKIES.get('name')
    pwd = request.COOKIES.get('pwd')
    return HttpResponse(f'获取到 cookie,name:{name},pwd:{pwd}')

16 django 之 Cookie、Session、Token

# 更新 cookie, 与设置一样
def set_cookie(request):
    obj = HttpResponse('重新对 cookie 进行了设置')
    obj.set_cookie('name','xing')
    obj.set_cookie('pwd','11122')
    return obj

16 django 之 Cookie、Session、Token

# 删除 cookie
def del_cookie(request):
    obj = HttpResponse('删除了一个 cookie')
    obj.delete_cookie('name')
    return obj

16 django 之 Cookie、Session、Token

3. 其他操作

  • cookie 加盐
# 为 cookie 进行加盐
def set_salt(request):
    obj = HttpResponse('为 name 加了个盐中盐')
    obj.set_cookie('name', 'shawn')
    # 加盐操作
    obj.set_signed_cookie('name', 'shawn', salt='盐中盐')
    return obj

# 获取加盐的 cookie
def get_salt(request):
    name_salt = request.COOKIES.get('name')
    salts = request.get_signed_cookie('name', salt='盐中盐')
    return HttpResponse(f'获取到加盐的 cookie 名:{salts}\n 加盐后的 cookie:{name_salt}')
  • 设置超时时间, 直接在设置 cookie 的时候加参数(两种方法)
# expires 常用, 支持 IE 浏览器(以秒为单位)
def set_timeout(request):
    obj = HttpResponse('超时删除 cookie')
    obj.set_cookie('name', 'shawn', max_age=5)  # 5 秒删除
    obj.set_cookie('pwd', '123445', expires=6)  # 6 秒删除
    return obj

4. 基于 cookie 的登入认证示例

登入了记录 cookie, 下次可以直接访问, 未登入则需要跳转到登录界面, 退出登入则删除 cookie

  • 登入认证装饰器(views.py)
def auth(func):
    def wrapper(request, *args, **kwargs):
        if request.COOKIES.get('name') == 'shawn':
            return func(request, *args, **kwargs)
        # print(request.get_full_path())  # 获取用户在 url 输入的地址
        # print(request.path)  # 获取用户在 url 输入的地址
        goto_url = request.get_full_path()  # 就是用户最开始想要访问的地址(这里看看他有没有登入)
        # 没有登入直接重定向到登入页面, 后面带上他想访问的地址
        return redirect(f'/login/?goto={goto_url}')

    return wrapper
  • 其他视图函数(views.py)
# 登入
def login(request):
    if request.method == "POST":
        name = request.POST.get('name')
        passwd = request.POST.get('passwd')
        # 拿到用户之前想访问的地址(可能用户是因为没登入才跳转过来登入)
        goto_url = request.GET.get('goto')
        if name == 'shawn' and passwd == '123':
            # 下面进行判断 goto_url 是否为空(因为用户可能是直接访问 login 页面的)
            if goto_url:
                obj = redirect(f'{goto_url}')
            else:
                obj = redirect('/home/')  # 如果是直接登入的就直接跳到首页
            # 登入成功保存用户 cookie 到浏览器
            obj.set_cookie('name', 'shawn')
            return obj
        # 用户输错密码再次展示登入界面并将他想去的地址再传一遍
        return render(request, 'login.html', {'goto_url': goto_url})
    elif request.method == 'GET':
        return render(request, 'login.html')


# home 登入后界面
@auth
def home(request):
    if request.method == "GET":
        return render(request, 'home.html')


# book 界面
@auth
def book(request):
    if request.method == "GET":
        return render(request, 'book.html')


# 退出登入: 删除 cookie
@auth
def logout(request):
    obj = redirect('login_name')
    obj.delete_cookie('name')
    return obj
  • 路由层(urls.py)
# cookie 登入认证路由
path('login/', views.login,name='login_name'),
path('home/', views.home,name='home_name'),
path('logout/', views.logout,name='logout_name'),
path('book/', views.book,name='book_name'),
  • 模板层 : login.html
<div class="container-fluid">
    <div class="row">
        <div class="col-md-6 col-md-offset-3">
            <div class="panel panel-default">
              <div class="panel-heading text-center">
                <h3 class="panel-title"> 登入 </h3>
              </div>
              <div class="panel-body">
                  <form action="{{goto_url}}" method="post">
                      <p> 用户名: <input type="text" name="name" class="form-control"></p>
                      <p> 密码: <input type="passwd" name="passwd" class="form-control"></p>
                      <input type="submit" value=" 登入 " class="btn btn-block btn-warning">
                  </form>
              </div>
            </div>
        </div>
    </div>
</div>
  • 模板层 : home.html
<div class="container-fluid">
    <div class="row">
        <div class="col-md-8 col-md-offset-2">
            <div class="jumbotron a1">
              <h2> 我是首页, 只展示给登入的用户!</h2>
              <p> 莫再说 </p>
                <form action="{% url 'logout_name' %}" method="post" >
                    <input type="submit" value=" 退出登入 " class="btn btn-warning">
                </form>
                <form action="{% url 'book_name' %}">
                    <input type="submit" value="To Book>>" class="btn btn-info pull-right">
                </form>
            </div>
        </div>
    </div>
</div>
  • 模板层 : book.html
<div class="container-fluid">
    <div class="row">
        <div class="col-md-8 col-md-offset-2">
            <div class="jumbotron">
              <div class="alert alert-success" role="alert">
                  <h2><a href="#" class="alert-link"> 登入的用户才能访问图书馆 </a></h2>
                </div>
                <div class="alert alert-info" role="alert">
                  <a href="#" class="alert-link"> 万里黄沙掏不尽 </a>
                    {% block book %}
                    <form action="{% url 'home_name' %}">
                        <input type="submit" value=" 返回 HOME" class="bnt btn-success btn-block">
                    </form>
                    {% endblock %}
                </div>
                <div class="alert alert-warning" role="alert">
                  <a href="#" class="alert-link">《爱德华的乔楚罗》</a>
                </div>
                <div class="alert alert-danger" role="alert">
                  <a href="#" class="alert-link">《戴猫的银镜》</a>
                </div>
              {# // " 省略......" #}
            </div>
        </div>
    </div>
</div>
  • 测试效果

16 django 之 Cookie、Session、Token

六.django 中 session 的使用

1.session 四件套

  • 设置 session
def set_session(request):
    request.session['name'] = 'song'
    request.session['pwd'] = '123'
    return HttpResponse('设置了一个 session')
  • 获取 session
def get_session(request):
    name = request.session.get('name')
    pwd = request.session['pwd']  # 两种方法都可以(这种找不到会报错)
    return HttpResponse(f'获取到 session:{name}-{pwd}')
  • 修改 session
def update_session(request):
    name1 = request.session.get('name')
    request.session['name'] = 'shawn'
    name2 = request.session.get('name')
    return HttpResponse(f'修改前{name1}, 修改后{name2}')
  • 删除 session(一)
def del_session(request):
    name1 = request.session.get('name')
    del request.session['name']  # 删除 session 中的 name 信息
    name2 = request.session.get('name')
    pwd = request.session['pwd']
    return HttpResponse(f'只删除 name, 删除前 name:{name1}, 删除后再获取 name:{name2},pwd:{pwd}还在')
  • 删除 session(二)
def del2_session(request):
    request.session.delete()  # 删除数据库(服务端)
    request.session.flush()  # 删除 cookie 和数据库(客户端和服务端)
    return HttpResponse('删除, 去刷新数据库可以发现空了')

16 django 之 Cookie、Session、Token

2. 基于 session 的登入认证示例

登入了记录 session, 下次可以直接访问, 未登入则需要跳转到登录界面, 退出登入则删除 session

  • 登入认证装饰器(views.py)
def login_auth(func):
    def inner(request, *args, **kwargs):
        # 判断是否已经有这个用户的 session
        if request.session.get('name') == 'shawn':
            return func(request, *args, **kwargs)
        # 拿到用户输入的想要访问的地址
        goto_url = request.get_full_path()
        return redirect(f'/session_login/?goto={goto_url}')

    return inner
  • 其他视图函数(views.py)
# 登入
def session_login(request):
    if request.method == "POST":
        name = request.POST.get('name')
        pwd = request.POST.get('pwd')
        goto_url = request.GET.get('goto')
        if name == 'shawn' and pwd == '123':
            request.session['name'] = name
            request.session['pwd'] = pwd
            if goto_url:
                return redirect(goto_url)
            else:
                return redirect('session_home_name')
        return render(request, 'session_login.html', {'goto_url': goto_url})
    elif request.method == 'GET':
        return render(request, 'session_login.html')


# home 頁面
@login_auth
def session_home(request):
    if request.method == "GET":
        return render(request, 'session_home.html')


# book 页面
@login_auth
def session_book(request):
    if request.method == "GET":
        return render(request, 'session_book.html')


# 退出登入
@login_auth
def session_logout(request):
    request.session.flush()
    return redirect('session_login_name')
  • 路由层(urls.py)
# 基于 session 登入认证
path('session_login/', views.session_login,name='session_login_name'),
path('session_home/', views.session_home,name='session_home_name'),
path('session_book/', views.session_book,name='session_book_name'),
path('session_logout/', views.session_logout,name='session_logout_name'),
  • 模板层与基于 cookie 模板层一样

  • 测试效果

16 django 之 Cookie、Session、Token

正文完
 1
shawn
版权声明:本站原创文章,由 shawn 2023-06-16发表,共计8308字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
评论(没有评论)