zoukankan      html  css  js  c++  java
  • Django之cookie与session、中间件

    cookie与session

    为什么会有cookie和session

    由于HTTP协议是无状态的,无法记住用户是谁,这样我们在每一次登陆的时候,都要重新输入密码,甚至如果不设置cookie,网页可能都请求不了

    保存在客户端浏览器上的键值对

    服务端设置在客户端浏览器上的键值对,也就意味着浏览器其实可以拒绝服务端的命令。默认情况下,浏览器都是直接让服务端设置键值对的

    在操作开始之前我们需要对三板斧进行变形

    obj1 = HttpResponse()
    return obj1
    obj2 = render()
    return obj2
    obj3 = redirect()
    return obj3
    

    设置cookie

    obj1.set_cookie()
    

    获取cookie

    request.COOKIES.get()
    

    删除cookie

    obj1.delete_cookie()
    

    实例:cookie版登录校验

    直接上代码:

    def login(request):
        # print(request.path_info)  # 只拿url 不拿get请求携带的额外参数
        # print(request.get_full_path())  # 都拿
        
        if request.method == "POST":
            username = request.POST.get('username')
            password = request.POST.get('password')
            if username == 'yjy' and password == '123':
                old_path = request.GET.get('next')
                if old_path:
                    # 保存用户登录状态
                    obj = redirect(old_path)
                else:
                    obj = redirect('/home/')
                obj.set_cookie('name', 'yjy')  # 让客户端浏览器 记录一个键值对
                # obj.set_cookie('name','jason',max_age=5)  # 让客户端浏览器 记录一个键值对
                return obj
        return render(request, 'login.html')
    
    
    from functools import wraps   #装饰器修复技术
    def login_auth(func):
        @wraps(func)
        def inner(request, *args, **kwargs):
            if request.COOKIES.get('name'):
                res = func(request, *args, **kwargs)
                return res
            else:
                target_url = request.path_info
                return redirect('/login/?next=%s' % target_url)
        return inner
    
    
    @login_auth
    def home(request):
        # 校验用户是否登录
        # if request.COOKIES.get('name'):
        #     return HttpResponse('我是主页 只有登录了才能看')
        # return redirect('/login/')
        return HttpResponse('我是主页 只有登录了才能看')
    
    
    @login_auth
    def index(request):
        return HttpResponse('我是index页面 也需要用户登录之后才能看')
    
    
    @login_auth
    def xxx(request):
        return HttpResponse('xxx页面 也是需要登录了之后才能看')
    
    
    @login_auth
    def logout(request):
        obj = redirect('/login/')
        obj.delete_cookie('name')  #注销之后删除cookie
        return obj
    

    session

    保存在服务器上的键值对

    django session默认的过期时间是14天

    设置session

     request.session['key'] = value   #仅仅只会在内存产生一个缓存
    

    三步骤:

    • django内部自动生成了随机的字符串
    • 在django_session表中存入数据

    session_key session_data date
    随机字符串1 数据1 ...
    随机字符串2 数据2 ...
    随机字符串3 数据3 ...

    • 将产生的随机字符串发送给浏览器 让浏览器保存到cookie中(sessionid:随机字符串)
    def set_session(request):
        request.session['username'] = 'yjy'
        request.session.set_expiry(value=0)   #session在关闭浏览器后消失
        return HttpResponse("设置session")
    

    获取session

    request.session..get('key')
    

    三步骤:

    • 浏览器发送cookie到django后端之后 django会自动获取到cookie值
    • 拿着随机字符串去django_session表中比对 是否有对应的数据
    • 如果比对上了 就讲随机字符串所对应的数据 取出赋值给request.session,如果对不上 那么request.session就是空

    session表中的一条记录针对一个浏览器,同一台电脑上,不同的浏览器来,才会有不同的记录

    def get_session(request):
        print(request.session.get('username'))
        return HttpResponse('获取session')
    

    删除session

    delete:删除服务端的

    request.session.delete()
    

    flush:浏览器和服务端全部删除

    request.session.flush()
    
    def delete_session(request):
        # request.session.delete()  #删除服务端的session
        
        request.session.flush()   #两个端的session都会删除
        return HttpResponse("删除session")
    

    session也可以设置超时时间

    request.session.set_expiry(value)
    
    • value为整数,session会在数秒后消失(以秒为单位)
    • value为 datatime或者timedelta时, session会在这个时间后消失
    • value为0,session会在关闭浏览器后消失
    • value为None,session会依赖全局session失效策略

    实例:session版登录校验

    后端

    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 == "yjy" and password == "123456":
                # 设置session值
                request.session['username'] = username
                # 获取跳到登陆之前的url
                next_url = request.GET.get("next")
                if next_url:
                    return redirect(next_url)
                else:
                    return redirect('/index/')
        return render(request, "login.html")
    
    # 装饰器
    from functools import wraps
    
    def check_login(func):
        @wraps(func)
        def inner(request, *args, **kwargs):
            next_url = request.get_full_path()
            print(next_url)
            if request.session.get('username'):
                return func(request, *args, **kwargs)
            else:
                return redirect(f"/login/?next={next_url}")
        #http://127.0.0.1:8000/login/?username=yjy&password=123456
        return inner
    
    @check_login
    def index(request):
        # request.session.get("username", None)
        return HttpResponse('我是index页面 需要用户登录之后才能看')
    

    前端:

    <form action="" method="post">
        {% csrf_token %}
        <p>username:<input type="text" name="username"></p>
        <p>password:<input type="text" name="password"></p>
        <button><input type="submit"></button>
    </form>
    

    最终结果是这样子的

    提交数据之后的显示

    数据库中session的显示

    django中间件

    应用场景

    用户访问频率限制
    用户是否是黑名单 白名单
    所有用户登录校验
    只要是涉及到网址全局的功能 中间件是不二之选

    自定义方法

    我们先要做好相应的数据准备

    1.新建一个文件夹 里面新建一个任意名称的py文件
    里面写类 固定继承

    from django.utils.deprecation import MiddlewareMixin
    class MyMiddle(MiddlewareMixin):
    	...
    

    2.去配置文件注册到中间件配置中
    需要手写字符串的路径

     'app01.mymiddleware.myaabb.MyMiddle1'
     'app02.mymiddleware.myaabb.MyMiddle2'
    

    process_request:

    请求来的时候 会从上往下依次经过每一个中间件里面process_request,一旦里面返回了HttpResponse对象那么就不再往后执行了 会执行同一级别的process_response

    def process_request(self,request):
    	print('我是第一个自定义中间件里面的process_request方法')
        return HttpResponse("我是第一个自定义中间件里面的HttpResponse对象返回值")  # 直接原地返回
    

    process_response:

    响应走的时候 会从下往上依次经过每一个中间件里面的process_response

    def process_response(self,request,response):  # response就是要返回给用户的数据
    	 print("我是第一个自定义中间件里面的process_response方法")
         return response  #只要有response参数,就必须给他返回
    

    process_view:

    路由匹配成功之后,执行视图函数之前触发

    process_exception:

    当视图函数出现异常(bug)的时候自动触发

    process_template_response:

    当视图函数执行完毕之后并且返回的对象中含有render方法的情况下才会触发

    django请求生命周期流程图

    中间件之前端操作

    form表单

    写form表单之前只需要加上{% csrf_token %}

    ajax

    第一种: 自己再页面上先通过{% csrf_token %}获取到随机字符串 然后利用标签查找

    data:{'username':'jason','csrfmiddlewaretoken':$('[name="csrfmiddlewaretoken"]').val()},
    

    第二种:

    data:{'username':'jason','csrfmiddlewaretoken':'{{ csrf_token }}'},
    

    第三种:拷贝js文件

    #这个东西在中间件的官网上拷贝就行了
    function getCookie(name) {
        var cookieValue = null;
        if (document.cookie && document.cookie !== '') {
            var cookies = document.cookie.split(';');
            for (var i = 0; i < cookies.length; i++) {
                var cookie = jQuery.trim(cookies[i]);
                // Does this cookie string begin with the name we want?
                if (cookie.substring(0, name.length + 1) === (name + '=')) {
                    cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                    break;
                }
            }
        }
        return cookieValue;
    }
    var csrftoken = getCookie('csrftoken');
    
    
    function csrfSafeMethod(method) {
      // these HTTP methods do not require CSRF protection
      return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
    }
    
    $.ajaxSetup({
      beforeSend: function (xhr, settings) {
        if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
          xhr.setRequestHeader("X-CSRFToken", csrftoken);
        }
      }
    });
    

    跨站请求伪造(csrf)

    原理:

    你写的form表单中 用户的用户名 密码都会真实的提交给银行后台

    但是收款人的账户却不是用户填的 你暴露给用户的是一个没有name属性的input框
    你自己提前写好了一个隐藏的带有name和value的input框

    钓鱼网站实例

    后端

    def transfer(request):
        if request.method == 'POST':
            username = request.POST.get('username')
            target_user = request.POST.get('target_user')
            money = request.POST.get('money')
            print('%s 给 %s转了%s钱' % (username, target_user, money))
        return render(request, 'transfer.html')
    

    正儿八经网站前端

    <form action="" method="post">
        <p>username:<input type="text" name="username"></p>
        <p>target_user:<input type="text" name="target_user"></p>
        <p>money:<input type="text" name="money"></p>
        <input type="submit">
    </form>
    

    钓鱼网站前端

    <form action="http://127.0.0.1:8000/transfer/" method="post">
        <p>username:<input type="text" name="username"></p>
        <p>targer_user:<input type="text"></p>
        <p><input type="text" name="target_user" value="jason" style="display: none"></p>
        <p>money:<input type="text" name="money"></p>
        <input type="submit">
    </form>
    

    防钓鱼网站策略

    只要是用户想要提交post请求的页面 我在返回给用户的时候就提前设置好一个随机字符串当用户提交post请求的时候 我会自动先取查找是否有该随机字符串
    如果有 正常提交,如果没有 直接报403

    以上仅仅是一个思路,还是需要我们用代码去实现,具体的实现方法就是在里面注入中间件。

    CBV加装饰器

    先要导入模块

    from django.views.decorators.csrf import csrf_exempt, csrf_protect
    from django.utils.decorators import method_decorator
    

    csrf_exempt 两种装饰方式

    第一种

    @method_decorator(csrf_exempt,name='dispatch')
    class MyCsrf(View):
    

    第二种

    @method_decorator(csrf_exempt)
    def dispatch(self, request, *args, **kwargs):
        return super().dispatch(request,*args,**kwargs)
    def get(self,request):
        return HttpResponse('hahaha')
    

    其他装饰器 三种装饰方式

    第一种

    @method_decorator(csrf_protect,name='post')
    class MyCsrf(View):
    

    第二种

    @method_decorator(csrf_protect)
    def dispatch(self, request, *args, **kwargs):
        return super().dispatch(request,*args,**kwargs)
    def get(self,request):
        return HttpResponse('hahaha')
    

    第三种

    @method_decorator(csrf_protect)
    def post(self,request):
       return HttpResponse('post'
    

    每日面试题

    python2和python3的区别(至少写三个)

    '''
    py2:
    >>> print("hello", "world")
    ('hello', 'world')
    py3:
    >>> print("hello", "world")
    hello world
    
    
    py2:input_raw()
    py3:input()
    
    
    1/2的结果
    py2:返回0
    py3:返回0.5
    
    
    py2:默认编码ascii
    py3:默认编码utf-8
    
    
    字符串
    py2:unicode类型表示字符串序列,str类型表示字节序列
    py3::str类型表示字符串序列,byte类型表示字节序列
    
    
    py2:函数用关键字global声明某个变量为全局变量,但是在嵌套函数中,想要给一个变量声明为非局部变量是没法实
    现的。
    py3:新增了关键字nonlocal,使得非局部变量成为可能
    
    
    py2:
     int() # 整型
     long() # 长整型
    py3:没有long类型,只有int类型
    
    
    py2:xrange 用法与 range 完全相同,所不同的是生成的不是一个list对象,而是一个生成器。
    py3:将以前的range取消了,而将xrange重新命名成了range!所以我们现在看到的range其实本质还是xrange~。
    
    
    py2: iteritems() 用于返回本身字典列表操作后的迭代器【Returns an iterator on allitems(key/value pairs) 】,不占用额外的内存。
    py3: iteritems()方法已经废除了。在3.x里用 items()替换iteritems() ,可以用于 for 来循环遍历
    '''
    

    什么是可变,什么是不可变

    '''
    可变不可变指的是内存中的值是否可以被改变,
    可变:值得改变不会引起内存地址的改变
    不可变:值得改变会引起内存地址的改变
    不可变类型有数值、字符串、元组;
    可变类型则是可以改变,主要有列表、字典。
    '''
    

    m=10,n=5,互换值(至少两种方式)

    '''
    t = m  #t=10
    m = n  #m=5
    n = t  #n=10
    
    
    m,n = n,m   #交叉赋值
    '''
    
  • 相关阅读:
    关于 Delphi 中的Sender和易混淆的概念(转)
    C#实现打印与打印预览功能(转)
    Quartz.NET
    如何从Powerdesigner进行数据建模并生成SQL脚本
    pentaho BI套件中PSW和PDI的连接
    Oracle中如何使用imp语言导入dmp文件
    DatePicker和DateEdit的区别
    dev控件中LookUpEdit的数据绑定问题
    如何在GridControl的某一列放入CheckBox、Button以及其他控件
    在GridControl中如何选中某一行中的某一列
  • 原文地址:https://www.cnblogs.com/yanjiayi098-001/p/11768375.html
Copyright © 2011-2022 走看看