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'
    
  • 相关阅读:
    ASP.NET CORE 使用Consul实现服务治理与健康检查(2)——源码篇
    ASP.NET CORE 使用Consul实现服务治理与健康检查(1)——概念篇
    Asp.Net Core 单元测试正确姿势
    如何通过 Docker 部署 Logstash 同步 Mysql 数据库数据到 ElasticSearch
    Asp.Net Core2.2 源码阅读系列——控制台日志源码解析
    使用VS Code 开发.NET CORE 程序指南
    .NetCore下ES查询驱动 PlainElastic .Net 升级官方驱动 Elasticsearch .Net
    重新认识 async/await 语法糖
    EF添加
    EF修改部分字段
  • 原文地址:https://www.cnblogs.com/Ghostant/p/12194014.html
Copyright © 2011-2022 走看看