• 🍖django之Cookie、Session、Token


    一.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
    

    image-20210329225140803

    image-20210329225432605

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

    image-20210329225343350

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

    image-20210329230248506

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

    image-20210329230853135

    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}
    加盐后的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>
    
    • 测试效果

    qqqqq

    六.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('删除,去刷新数据库可以发现空了')
    

    wwwwww

    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模板层一样

    • 测试效果

    aaaaaaaaaaaaa

  • 相关阅读:
    《七哥说道》第十八章:何处不风雨,套路说江湖
    《七哥说道》第十七章:北漂青年,人海茫茫
    《闲扯Redis四》List数据类型底层编码转换
    《闲扯Redis三》Redis五种数据类型之List型
    《闲扯Redis二》String数据类型之底层解析
    《闲扯Redis一》五种数据类型之String型
    Js解析Json数据获取元素JsonPath与深度
    《七哥说道》第十六章:程序员,江湖见
    Swagger2.9.2进入API界面报NumberFormatException异常
    绝顶高手必经之路【资源共享】
  • 原文地址:https://www.cnblogs.com/songhaixing/p/14617397.html
Copyright © 2020-2023  润新知