django中间件和auth模块

Django中间件

 

 由django的生命周期图我们可以看出,django的中间件就类似于django的保安,请求一个相应时要先通过中间件才能到达django后端(url、views、template、models),同样后端进行响应的时候也需要经过中间件才能达到web服务网关。

django的七个中间件

MIDDLEWARE = [
                'django.middleware.security.SecurityMiddleware',
                #  一些安全设置,比如XSS脚本过滤

                'django.contrib.sessions.middleware.SessionMiddleware',
                #  session支持中间件,加入这个中间件,会在数据库中生成一个django_session的表。
 
                'django.middleware.common.CommonMiddleware',
                #  通用中间件,会处理一些URL,比如baidu.com会自动的处理成www.baidu.com。比如/blog/111会处理成/blog/111/自动加上反斜杠。

                'django.middleware.csrf.CsrfViewMiddleware',
                 # 跨域请求伪造中间件。加入这个中间件,在提交表单的时候会必须加入csrf_token,cookie中也会生成一个名叫csrftoken的值,也会在header中加入一个HTTP_X_CSRFTOKEN的值来放置CSRF攻击。

                'django.contrib.auth.middleware.AuthenticationMiddleware',
                #  用户授权中间件。他会在每个HttpRequest对象到达view之前添加当前登录用户的user属性,也就是你可以在view中通过request访问user。

                'django.contrib.messages.middleware.MessageMiddleware',
                #  消息中间件。展示一些后台信息给前端页面。如果需要用到消息,还需要在INSTALLED_APPS中添加django.contrib.message才能有效。如果不需要,可以把这两个都删除。

                'django.middleware.clickjacking.XFrameOptionsMiddleware',
                #  防止通过浏览器页面跨Frame出现clickjacking(欺骗点击)攻击出现。
            ]        

django中间的自定义方法

中间件可以定义五个方法,分别是:(主要的是process_request和process_response)

  • process_request(self,request)
  • process_view(self, request, view_func, view_args, view_kwargs)
  • process_template_response(self,request,response)
  • process_exception(self, request, exception)
  • process_response(self, request, response)

自定义中间件的示例

 

 

 1.process_request()方法

规律
  1.请求来的时候 会经过每个中间件里面的process_request方法(从上往下)
  2.如果方法里面直接返回了HttpResponse对象 那么会直接返回 不再往下执行
基于该特点就可以做访问频率限制,身份校验,权限校验

2.process_response()方法

规律
  1.必须将response形参返回 因为这个形参指代的就是要返回给前端的数据
  2.响应走的时候 会依次经过每一个中间件里面的process_response方法(从下往上)

3.process_view()方法

  1.在路由匹配成功执行视图函数之前 触发

4.process_exception()方法

  1.当你的视图函数报错时  就会自动执行

5.process_template_response()方法

  1.当你返回的HttpResponse对象中必须包含render属性才会触发

def index(request):
    print('我是index视图函数')
    def render():
        return HttpResponse('什么鬼玩意')
    obj = HttpResponse('index')
    obj.render = render
    return obj

总结:以上方法的返回值可以是None或一个HttpResponse对象,如果是None,则继续按照django定义的规则向后继续执行,如果是HttpResponse对象,则直接将该对象返回给用户。

中间件的proce_request方法是在执行视图函数之前执行的。

当配置多个中间件时,会按照MIDDLEWARE中的注册顺序,也就是列表的索引值,从前到后依次执行的。

不同的中间件之间传递的request都是同一个对象。

如果需要自己写的中间件生效,必须继承MiddlewareMixin,而且要保证在注册时路径不能写错。

csrf跨站请求伪造

关于钓鱼网站的原理,比如说你登录了一个钓鱼网站的页面,和中国银行一模一样的页面,你在哪里进行转账操作,它的转账信息也确实发到了中国银行,你的账户确实也扣钱了,但是唯一不对的时收款人不是你输入的那个人,那是因为它在用户输入框的input上做了手脚,这个input没有设置name属性,而在内部,隐藏的标签里,有一个写好了name和value的input框,这样你只要点击提交,那个value(钓鱼网站受益人的账户)就会和你的转账信息一起发给中国银行。

防止钓鱼网站的思路

网站会给返回给用户的form表单页面 偷偷塞一个随机字符串
请求到来的时候 会先比对随机字符串是否一致 如果不一致 直接拒绝(403)
该随机字符串有以下特点
1.同一个浏览器每一次访问都不一样
2.不同浏览器绝对不会重复

通过{% csrf_token %}来生成随机字符串

1.form表单发送post请求的时候  需要你做得仅仅书写一句话

{% csrf_token %}

2.ajax发送post请求 如何避免csrf校验

1.现在页面上写{% csrf_token %},利用标签查找  获取到该input键值信息
    {'username':'jason','csrfmiddlewaretoken':$('[name=csrfmiddlewaretoken]').val()}
    $('[name=csrfmiddlewaretoken]').val()
    
2.直接书写'{{ csrf_token }}'
    {'username':'jason','csrfmiddlewaretoken':'{{ csrf_token }}'}
    {{ csrf_token }}

3.你可以将该获取随机键值对的方法 写到一个js文件中,之后只需要导入该文件即可
    新建一个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的时候,又有几个不需要校验的该如何处理,相反如果你的网站全局不需要校验csrf的时候,又有几个需要校验的功能又该怎么处理。

#先导入模块
from django.utils.decorators import method_decorator    
from django.views.decorators.csrf import csrf_exempt,csrf_protect

当整个网站都不校验,只想某个功能校验时

# 第一种方式
# @method_decorator(csrf_protect,name='post')  # 有效的
class MyView(View):
    # 第三种方式
    # @method_decorator(csrf_protect)
    def dispatch(self, request, *args, **kwargs):
        res = super().dispatch(request, *args, **kwargs)
        return res

    def get(self,request):
        return HttpResponse('get')
    # 第二种方式
    # @method_decorator(csrf_protect)  # 有效的
    def post(self,request):
        return HttpResponse('post')

当整个网站都校验,只想某个功能不校验时

#如果是csrf_exempt 只有两种(只能给dispatch装)   特例
@method_decorator(csrf_exempt,name='dispatch')  # 第二种可以不校验的方式
class MyView(View):
    # @method_decorator(csrf_exempt)  # 第一种可以不校验的方式
    def dispatch(self, request, *args, **kwargs):
        res = super().dispatch(request, *args, **kwargs)
        return res

    def get(self,request):
        return HttpResponse('get')

    def post(self,request):
        return HttpResponse('post')

总结:装饰器中只有csrf_exempt是特例,其他的装饰器在给CBV装饰的时候 都可以有三种方式

Auth模块

1、Auth模块是什么

Auth模块是Django自带的用户认证模块:

我们在开发一个网站的时候,无可避免的需要设计实现网站的用户系统。此时我们需要实现包括用户注册、用户登录、用户认证、注销、修改密码等功能,这还真是个麻烦的事情呢。

Django作为一个完美主义者的终极框架,当然也会想到用户的这些痛点。它内置了强大的用户认证系统--auth,它默认使用 auth_user 表来存储用户数据。

要注意的时,使用auth模块的话最好用全套。

createsuperuser   #创建超级用户 这个超级用户就可以拥有登陆django admin后台管理的权限

auth模块的功能

    #查询用户
        from django.contrib import auth
        user_obj = auth.authenticate(username=username,password=password)  # 必须要用 因为数据库中的密码字段是密文的 而你获取的用户输入的是明文
    #记录用户状态
        auth.login(request,user_obj)  # 将用户状态记录到session中
    #判断用户是否登录
        print(request.user.is_authenticated)  # 判断用户是否登录  如果是你们用户会返回False
    #用户登录之后 获取用户对象
        print(request.user)  # 如果没有执行auth.login那么拿到的是匿名用户
    #校验用户是否登录
        from django.contrib.auth.decorators import  login_required
        @login_required(login_url='/xxx/')  # 局部配置
        def index(request):
            pass
        
        # 全局配置  settings文件中
        LOGIN_URL = '/xxx/'
    #验证密码是否正确
        request.user.check_password(old_password)
    #修改密码    
        request.user.set_password(new_password)
        request.user.save()  # 修改密码的时候 一定要save保存 否则无法生效
    #退出登陆
        auth.logout(request)  # request.session.flush()
    #注册用户
            # User.objects.create(username =username,password=password)  # #创建用户名的时候 千万不要再使用create 了
            # User.objects.create_user(username =username,password=password)  # 创建普通用户
            User.objects.create_superuser(username =username,password=password,email='123@qq.com')  # 创建超级用户  邮箱必填

自定义auth_user表

from django.contrib.auth.models import AbstractUser
# Create your models here.
# 第一种 使用一对一关系  不考虑

# 第二种方式   使用类的继承
class Userinfo(AbstractUser):
    # 千万不要跟原来表中的字段重复 只能创新
    phone = models.BigIntegerField()
    avatar = models.CharField(max_length=32)

# 一定要在配置文件中 告诉django
# 告诉django  orm不再使用auth默认的表  而是使用你自定义的表
AUTH_USER_MODEL = 'app01.Userinfo'  # '应用名.类名'
"""
1.执行数据库迁移命令
    所有的auth模块功能 全部都基于你创建的表 
    而不再使用auth_user
"""

 

posted @ 2019-09-25 20:37  云上fly  阅读(400)  评论(0编辑  收藏  举报