django框架

今日内容:

1.django中间件

2.csrf跨站请求伪造

3.auth模块

4.settings功能插拔式源码

 

django流程图(重点)

 

 

 

1.django中间件

django中间件就类似于是django的保安,请求的时候需要先经过中间件才能到达django后端
(urls,views,templates,models),响应走的时候也需要经过中间件才能到达web服务网关接口。

django有他自己默认的七个中间件:

            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中间件是用来干什么的(重要)

1.网站全局的校验,访问频率限制,权限校验,只要是涉及到全局的校验你都可以在中间件中完成
2.django的中间件是所有web框架中,做的最好的一个。

 

django中间件中有五个用户可以自定义的方法:

需要掌握的
1.process_request()方法
2.process_response()方法
需要了解的方法
3.process_view()
4.process_exception()
5.process_template_response()

 

接下来就介绍这5个方法:

1.process_request()方法

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

注意:
代码:
创建一个mymiddleware文件夹
 1 from django.utils.deprecation import MiddlewareMixin
 2 from django.shortcuts import HttpResponse
 3 
 4 class MyMdd(MiddlewareMixin):
 5     def process_request(self,request):
 6         print('我是第一个中间件里面的process_request方法')
 7         # return HttpResponse('123')
 8 
 9 class MyMdd1(MiddlewareMixin):
10     def process_request(self,request):
11         print('我是第二个中间件里面的process_request方法')
View Code

views里面:

1 def index(request):
2     print('我是index视图函数')
3     return HttpResponse('index')
View Code

 

2.process_response()方法

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

代码:
 1 from django.utils.deprecation import MiddlewareMixin
 2 from django.shortcuts import HttpResponse
 3 
 4 class MyMdd(MiddlewareMixin):
 5     def process_request(self,request):
 6         print('我是第一个中间件里面的process_request方法')
 7         # return HttpResponse('123')
 8 
 9     def process_response(self,request,response):
10         print('我是第一个中间件里面的process_response方法')
11         return response
12 
13 
14 
15 class MyMdd1(MiddlewareMixin):
16     def process_request(self,request):
17         print('我是第二个中间件里面的process_request方法')
18 
19     def process_response(self,request,response):
20         print('我是第二个中间件里面的process_response方法')
21         return response
View Code

 

需要了解的方法:

需要了解的方法
要了解的方法
                        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
                总结:你在书写中间件的时候 只要形参中有repsonse 你就顺手将其返回 这个reponse就是要给前端的消息
                
                
                如何自定义我们自己的中间件,研究这上面五个方法都有哪些特点
                        1.如果你想让你写的中间件生效 就必须要先继承MiddlewareMixin
                        2.在注册自定义中间件的时候 一定要确保路径不要写错
代码:
 1 class MyMdd(MiddlewareMixin):
 2     def process_request(self,request):
 3         print('我是第一个中间件里面的process_request方法')
 4 
 5 
 6     def process_response(self,request,response):
 7         print('我是第一个中间件里面的process_response方法')
 8         return response
 9 
10     def process_view(self,request,view_func,view_args,view_kwargs):
11         print(view_func)
12         print(view_args)
13         print(view_kwargs)
14         print('我是第一个中间件里面的process_view方法')
15 
16     def process_exception(self, request, exception):
17         print('我是第一个中间件里面的process_exception')
18 
19     def process_template_response(self, request, response):
20         print('我是第一个中间件里面的process_template_response')
21         return response
22 
23 
24 class MyMdd1(MiddlewareMixin):
25     def process_request(self,request):
26         print('我是第二个中间件里面的process_request方法')
27 
28     def process_response(self,request,response):
29         print('我是第二个中间件里面的process_response方法')
30         return response
31     def process_view(self,request,view_func,view_args,view_kwargs):
32         print(view_func)
33         print(view_args)
34         print(view_kwargs)
35         print('我是第二个中间件里面的process_view方法')
36 
37 
38     def process_exception(self, request, exception):
39         print('我是第二个中间件里面的process_exception')
40 
41     def process_template_response(self, request, response):
42         print('我是第二个中间件里面的process_template_response')
43         return response
View Code

 

 

2.csrf跨站请求伪造:

什么是钓鱼网站:
    就是通过制作一个跟正儿八经的网站一模一样的页面,
    骗取用户输入信息,转账交易,从而做手脚 案例: 比如说转账交易的请求确确实实是发给了中国银行,
账户钱也确确实实少了,唯一不一样的是收款人的账户不对。 内部的原理: 在让用户输入对方账户的那个input框上面做手脚,给这个input框不设置name属性,
在内部隐藏一个事先写好的name和value属性的input框,这个value的值,就是钓鱼网站受益人的账号 防止钓鱼网站的思路: 网站会给返回的用户的form表单页面,偷偷塞一个随机字符串,
请求到来的时候,会先比对随机字符串是否一致,如果不一致,直接拒绝(
403) 这就解释了为什么以前每一次都把中间件的一个中间件给注释了。 该随时字符串有一下特点: 1.同一个浏览器每一次访问都不一样 2.不同的浏览器绝对不会重复

 

正规网站:

后端:

1 def transfer(request):
2     if request.method == 'POST':
3         username = request.POST.get('username')
4         money = request.POST.get('money')
5         target_user = request.POST.get('target_user')
6         print('%s 给 %s 转了 %s元'%(username,target_user,money))
7     return render(request,'t.html')
View Code

前端:

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Title</title>
 6     <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
 7 </head>
 8 <body>
 9 <h2>这是正儿八经的网站</h2>
10 <form action="" method="post">
11     {% csrf_token %} 
12     <p>本人用户名:<input type="text" name="username"></p>
13     <p>转账金额:<input type="text" name="money"></p>
14     <p>对方账户:<input type="text" name="target_user"></p>
15     <input type="submit">
16 </form>
17 
18 </body>
19 </html>
View Code

钓鱼网站:

前端:

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Title</title>
 6     <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
 7 </head>
 8 <body>
 9 <h2>这是钓鱼网站</h2>
10 <form action="http://127.0.0.1:8000/transfer/" method="post">
11     <p>本人用户名:<input type="text" name="username"></p>
12     <p>转账金额:<input type="text" name="money"></p>
13     <p>对方账户:<input type="text"></p>
14     <input type="text" name="target_user" value="jason" style="display: none">
15     <input type="submit">
16 </form>
17 </body>
18 </html>
View Code

总结:1.form表单发送post请求的时候,需要你做的仅仅就是书写一句话:{% csrf_token %}

 

2.Ajax发送post请求时,该如何避免csrf校验

前端:

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Title</title>
 6     <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
 7 </head>
 8 <body>
 9 <h2>这是正儿八经的网站</h2>
10 <form action="/lll/" method="post">
11 {#    {% csrf_token %}#}
12     <p>本人用户名:<input type="text" name="username"></p>
13     <p>转账金额:<input type="text" name="money"></p>
14     <p>对方账户:<input type="text" name="target_user"></p>
15     <input type="submit">
16 </form>
17 {#<button id="b1">发送ajax请求</button>#}
18 
19 {% load static %}
20 {#<script src="{% static 'setjs.js' %}"></script>#}
21 <script>
22     {#$('#b1').click(function () {#}
23     {#    $.ajax({#}
24     {#        url:'',#}
25     {#        type:'post',#}
26     {#        // 第一种方式#}
27             {#data:{'username':'jason','csrfmiddlewaretoken':$('[name=csrfmiddlewaretoken]').val()},#}
28     {#        // 第二种方式#}
29             {#data:{'username':'jason','csrfmiddlewaretoken':'{{ csrf_token }}'},#}
30     {#        // 第三种方式 :直接引入js文件#}
31     {#        data:{'username':'jason'},#}
32     {#        success:function (data) {#}
33     {#            alert(data)#}
34     {#        }#}
35     {##}
36     {#    })#}
37     // {})
38 </script>
39 </body>
40 </html>
View Code
    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文件 存放以下代码 之后导入即可 
  导入的代码:
 1 function getCookie(name) {
 2                     var cookieValue = null;
 3                     if (document.cookie && document.cookie !== '') {
 4                         var cookies = document.cookie.split(';');
 5                         for (var i = 0; i < cookies.length; i++) {
 6                             var cookie = jQuery.trim(cookies[i]);
 7                             // Does this cookie string begin with the name we want?
 8                             if (cookie.substring(0, name.length + 1) === (name + '=')) {
 9                                 cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
10                                 break;
11                             }
12                         }
13                     }
14                     return cookieValue;
15                 }
16                 var csrftoken = getCookie('csrftoken');
17 
18 
19                 function csrfSafeMethod(method) {
20                   // these HTTP methods do not require CSRF protection
21                   return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
22                 }
23 
24                 $.ajaxSetup({
25                   beforeSend: function (xhr, settings) {
26                     if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
27                       xhr.setRequestHeader("X-CSRFToken", csrftoken);
28                     }
29                   }
30                 });
31         
View Code

 

 

1.当你网站全局都需要校验csrf的时候,有几个不需要校验该如何处理:

2.当你网站全局不校验csrf的时候 有几个需要校验又该如何处理 :

from django.views.decorators.csrf import csrf_exempt,csrf_protect
1.@csrf_exempt
def login(request):
    return HttpResponse('login')


2.@csrf_protect
def lll(request):
    return HttpResponse('lll')

 

在CBV中该如何装饰:

from django.utils.decorators import method_decorator    
            from django.views.decorators.csrf import csrf_exempt,csrf_protect
            # 这两个装饰器在给CBV装饰的时候 有一定的区别
            如果是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模块:

auth模块
            如果你想用auth模块   那么你就用全套
            
            
            
            跟用户相关的功能模块
                用户的注册 登陆 验证 修改密码 ...
            
            执行数据库迁移命令之后  会生成很多表  其中的auth_user是一张用户相关的表格
            添加数据
                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'  # '应用名.类名'
        
from django.contrib.auth.decorators import  login_required
@login_required # 自动校验当前用户是否登录 如果没有登录 默认跳转到 一个莫名其妙的登陆页面
1.执行数据库迁移命令 所有的auth模块功能 全部都基于你创建的表 而不再使用auth_user

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  

 

posted @ 2019-09-25 21:56  ZHANGYUZY  阅读(161)  评论(0编辑  收藏  举报