zoukankan      html  css  js  c++  java
  • django中间件和常用模块

    django中间件是http请求在经过wsgiref网关后在抵达路由系统之前所经过的一系列对数据的校验和处理。

    因为所有的http请求都会经由中间件处理,所以中间件有关的绝大数是全局相关的功能,例如黑名单、白名单、全局用户身份校验、全局用户访问频率校验。

    1.django自带的中间件

    MIDDLEWARE = [
        'django.middleware.security.SecurityMiddleware',
        'django.contrib.sessions.middleware.SessionMiddleware',
        'django.middleware.common.CommonMiddleware',
        'django.middleware.csrf.CsrfViewMiddleware',
        'django.contrib.auth.middleware.AuthenticationMiddleware',
        'django.contrib.messages.middleware.MessageMiddleware',
        'django.middleware.clickjacking.XFrameOptionsMiddleware',
    ]
    

    django支持自定义中间件

    from django.utils.deprecation import MiddlewareMixin
    
    class Mymiddleware(MiddlewareMixin):
        def process_request(self,request):  # 请求过来时执行的函数
            pass
        
        def process_response(self,request,response): # 响应返回时
            pass
        
        def process_view(self,request) # 匹配成功执行视图函数前触发
        def process_template_response # 返回的reponse对象必须有render属性
        def exception # 视图函数异常出错时触发
    

    2.跨站请求伪造csrf

    Cross-site request forgery,概括的来说服务器收到的请求的确发自用户的浏览器,但却不知道请求本身是否是用户自愿发出的。

    # 假如一家银行用以运行转账操作的URL地址如下:
    http://www.examplebank.com/withdraw?account=AccoutName&amount=1000&for=PayeeName
    # 那么,一个恶意攻击者可以在另一个网站上放置如下代码: 
    <img src="http://www.examplebank.com/withdraw?account=Alice&amount=1000&for=Badman">
    

    在用户不知情的情况下会向银行发送转账请求,却不是用户的自愿行为。所以需要对服务器的安全性验证进行升级,csrf由此而来。

    服务器会给每个有post或get请求的网页随机生成一串字符串csrf_token,当用户发送post提交时必须携带上这个随机字符串,不然在django中间件时就会将本次http请求拦截。

    form表单携带csrf校验

    <!-- 在form表单内写入 -->
    {% csrf_token %}
    

    ajax携带csrf校验

    // 第一种方式 自己手动获取
    {#data:{'username':'jason','csrfmiddlewaretoken':$('input[name="csrfmiddlewaretoken"]').val()},#}
    // 第二种方式 利用模板语法
    {#data:{'username':'jason','csrfmiddlewaretoken':'{{ csrf_token }}'},#}
    // 第三种     通用方式 引入外部js文件  官网提供的方式
    {% load static %}
    <script src="{% static 'myset.js' %}"></script>
    data:{'username':'yyh'}
    

    myset.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);
        }
      }
    });
    

    3.csrf相关装饰器

    当全局时csrf校验而有些视图函数不需要csrf校验时

    from django.views.decorators.csrf import csrf_exempt
    from django.http import HttpResponse
    
    @csrf_exempt
    def home(request):
        return HttpResponse('home page')
    

    当全局不设置csrf校验而有些视图函数需要csrf校验时

    from django.views.decorators.csrf import csrf_exempt
    from django.http import HttpResponse
    
    @csrf_protect
    def home(request):
        return HttpResponse('home page')
    

    当视图函数基于CBV时

    # @method_decorator(csrf_protect,name='post')  # 第二种指名道姓的给类中某个方法装
    # @method_decorator(csrf_exempt,name='post')  # csrf_exempt 第二种方式不行
    @method_decorator(csrf_exempt,name='dispatch')  # 可以!!!
    class MyHome(View):  # APIView
        # @method_decorator(csrf_protect)  # 第三种 类中所有的方法都装
        # @method_decorator(csrf_exempt)  # csrf_exempt 第三种方式可以
        def dispatch(self, request, *args, **kwargs):
            return super().dispatch(request,*args,**kwargs)
    
        def get(self,request):
            return HttpResponse('get')
        # @method_decorator(csrf_protect)  # 第一种方式
        # @method_decorator(csrf_exempt)  # csrf_exempt 第一种方式不行
        def post(self,request):
            return HttpResponse('post')
    

    详见django官方文档 https://docs.djangoproject.com/en/1.11/ref/csrf/

    4.auth模块

    from django.utils.safestring import mark_safe
    from django.contrib.auth.models import User
    from django.contrib.auth.decorators import login_required
    

    1.创建用户

    from django.contrib.auth.models import User
    
    def register(request):
        if request.method == 'GET':
            return render(request, 'register.html')
        username = request.POST.get('username')
        password = request.POST.get('password')
        obj = User.objects.create_user(username=username,password=password)
        print(obj)
        return HttpResponse('注册成功')
    

    2.校验用户名登录

    from django.contrib.auth.models import User
    
    def login(request):
        if request.method=='GET':
            return render(request,'login.html')
        username = request.POST.get('username')
        password = request.POST.get('password')
        user_obj = auth.authenticate(username=username,password=password)
        # 校验成功返回用户对象,否则为None
        if user_obj:
            return HttpResponse('登录成功')
        return HttpResponse('登录失败')
    

    3.保存用户登录状态

    from django.contrib.auth.models import User
    
    def login(request):
        if request.method=='GET':
            return render(request,'login.html')
        username = request.POST.get('username')
        password = request.POST.get('password')
        user_obj = auth.authenticate(username=username,password=password)
        # 校验成功返回用户对象,否则为None
        if user_obj:
            # 此后都可通过request.user获取用户对象(保存了session值)
            auth.login(request,user_obj)
            return HttpResponse('登录成功')
        return HttpResponse('登录失败')
    

    4.如何判断当前用户是否登录以及如何获取当前登录用户

    def home(request):
    	# 未登录时为 AnonymousUser
        print(request.user)
        # 判断用户是否已经登录,返回True或False
        print(request.user.is_authenticated())
        if request.user.is_authenticated():
            return HttpResponse('已登录')
        else:
            return HttpResponse('未登录')
    

    5.校验用户是否登录

    from django.contrib.auth.decorators import login_required
    
    # 局部配置装饰器校验失败跳转url
    @login_required(login_url='/login/')
    def index(request):
        # request.user获取用户记录对象
        info = str(request.user.last_login) + str(request.user.password) + str(request.user.username)
        return HttpResponse(info)
    
    # 全局配置
    settings.py
    -----------------------------------------
    LOGIN_URL = '/login/'
    -----------------------------------------
    views.py
    -----------------------------------------
    @login_required
    def index(request):
        # request.user获取用户记录对象
        info = str(request.user.last_login) + str(request.user.password) + str(request.user.username)
        return HttpResponse(info)
    

    6.用户修改密码

    @login_required
    def set_password(request):
        user_obj = request.user
        if request.method == 'GET':
            return render(request,'set_password.html',locals())
        old_password = request.POST.get('old_password')
        new_password = request.POST.get('new_password')
        # check_password
        is_true = user_obj.check_password(old_password) 
        if is_true:
            # set_password
            user_obj.set_password(new_password)
            # 一定要save
            user_obj.save()
            return HttpResponse('修改密码成功')
        else:
            return HttpResponse('修改密码失败')
    

    7.用户注销

    @login_required
    def logout(request):
        res = auth.logout(request)
        print(res)
        return HttpResponse('注销成功')
    

    5.扩展auth_user表

    django为我们提供了默认了auth_user表,有时候该表不一定能满足我们的需求,所以需要我们手动来扩展表

    # 类的继承
    models.py
    --------------------------------------------
    from django.contrib.auth.models import User, AbstractUser
    
    class Userinfo(AbstractUser):
        phone = models.BigIntegerField(null=True)
        avatar = models.FileField(null=True)
        # 拓展的字段不要与原先表中的字段冲突
        
        
    settings.py
    -------------------------------------------------
    AUTH_USER_MODEL = 'app01.Userinfo'
    
  • 相关阅读:
    2020-02-26 今天学了啥?
    2020-02-25 今天学了啥?
    CSS选择器世界
    2019.12.21---今天学了啥?
    2019.12.20--今天学了啥?
    2019.12.19----今天学了啥?
    重拾算法之复杂度分析(大O表示法)
    es6之后,真的不需要知道原型链了吗?
    你真的了解FastClick吗?
    JavaScript中的对象与原型—你不知道的JavaScript上卷读书笔记(四)
  • 原文地址:https://www.cnblogs.com/Ghostant/p/12194014.html
Copyright © 2011-2022 走看看