Django- middleware -csrf extension request forgery intercept module middleware -Django Auth - follow django middleware plug-in configured to implement the function effect -09

Yesterday added: decorate their written login_auth mounted on CBV

Class inside the method are generally binding class method or object binding method, the first parameter is the class or object itself , the previous write decorators should change the parameters to be used, but here we can write to us with django good decorator, change does not require written decorator from

Three ways ( Remember guide module )

from django.utils.decorators import method_decorator

# @method_decorator(login_auth, name='get')  # 第一种, name 参数必须指定
class MyHome(View):
    # @method_decorator(login_auth)  # 第二种, get 和 post 都会被装饰(登录验证)(直接把 dispatch 拿过来,加个装饰器)
    def dispatch(self, request, *args, **kwargs):
        super().dispatch(request, *args, **kwargs)
     
    @method_decorator(login_auth)  # 第三种,直接装饰在单个方法上
    def get(self, request):
        return HttpResponse('get')
    
    def post(self, request):
        return HttpResponse('post')

django middleware

django django middleware is similar to a gateway, when the request needs to go through to get django middleware backend (urls), respond to take the time to go through middleware to reach the web service gateway interface (wsgif module)

django middleware can be used to do what

  • Do site global identity check, limiting the frequency of access, permissions check (anti-climb) ... as long as it relates to the overall verification can be done in almost middleware , it is also the first time the thought of middleware

django middleware design is more perfect, logical clearest and most simple (flask middleware inferior to it)

This middleware finished ahead of us will know why every request submitted post will be written on this go settings.py in the csrf middleware commented out temporarily

django request lifecycle *****

After middleware to enter urls.py (views.py ... then layer by layer progression)

Popular Science:

  1. wsgiref is not able to withstand high concurrency , so that the line will be replaced after uwsgi module (front plus a reverse proxy do nginx)
  • WSGI and what it means, respectively wsgi and uwsgi

WSGI is a protocol standard, wsgiref and uwsgi are achieved WSGI protocol function modules

  1. Upon entering request will go to the first intermediate layer is decided whether or not the cache data in the database
  • If any, will directly get the data and returns the requested (this can save resources, reduce the pressure on the server and database)
  • If not, then we will go middleware layer by layer, and then routing configuration, views.py ..., and so came to the last layer of middleware request again, while the returned data will be stored in a cache database in. (Next time you can get directly in the cache database data)

Specific principles and other post related to the expansion in terms of the concept on the line to know

The default method is probably composed of middleware and

There are seven default django middleware

django supports user-defined own middleware, and exposed to the user, can also expose five custom method middleware to the user

# settings.py 里的七个默认中间件
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',
]

Observation point into the source code middleware

'''
django.middleware.security.SecurityMiddleware
--> 本质是动态导入(可以看最后面的那个模仿案例) 
# from django.middleware.security import SecurityMiddleware

django.middleware.csrf.CsrfViewMiddleware
--> from django.middleware.csrf import CsrfViewMiddleware
'''

Found django middleware has five user-definable methods

# django.middleware.csrf.CsrfViewMiddleware  --> from django.middleware.csrf import CsrfViewMiddleware
class CsrfViewMiddleware(MiddlewareMixin):
    def _accept(self, request):
    def _reject(self, request, reason):
    def _get_token(self, request):
    def _set_token(self, request, response):
    def process_request(self, request):
    def process_view(self, request, callback, callback_args, callback_kwargs):
    def process_response(self, request, response):

# django.middleware.security.SecurityMiddleware  --> django.middleware.security.SecurityMiddleware
class SecurityMiddleware(MiddlewareMixin):
    def __init__(self, get_response=None):
    def process_request(self, request):
    def process_response(self, request, response):      

# django.contrib.sessions.middleware.SessionMiddleware
class SessionMiddleware(MiddlewareMixin):
    def __init__(self, get_response=None):
    def process_request(self, request):
    def process_response(self, request, response):
  • We need to master methods
  1. process_ request () method
  2. process_ response () method
  • You need to understand the way
  1. process_ view()
  2. process exception ()
  3. process_ template_ response ()

Middleware execution order

Roughly the same django request lifecycle that picture may be affected by the following conditions

Custom operations middleware explore the effects of different order of execution middleware

Test ideas:

  • Sign up different middleware in settings.py, the default execution order inquiry
  • What is the impact on different middleware process_request and process_response methods in return HttpResponse objects will execute the order
  • Five ways to understand the timing of the trigger

Custom Middleware

  1. Create a new folder (on a global or within app)
  2. Write a class inherits MiddlewareMiXin class
  3. Writing inside required (five in some methods) Method
  4. Be sure to configure the middleware in settings.py

Code

mymiddleware / mdd.py custom middleware

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse


class MyMdd(MiddlewareMixin):
    def process_request(self, request):
        print('我是第一个中间件里面的process_request方法')

    def process_response(self, request, response):
        print('我是第一个中间件里面的process_response方法')
        return response

    def process_view(self, request, view_func, view_args, view_kwargs):
        print(view_func)
        print(view_args)
        print(view_kwargs)
        print('我是第一个中间件里面的process_view方法')

    def process_exception(self, request, exception):
        print('我是第一个中间件里面的process_exception')

    def process_template_response(self, request, response):
        print('我是第一个中间件里面的process_template_response')
        return response


class MyMdd1(MiddlewareMixin):
    def process_request(self, request):
        print('我是第二个中间件里面的process_request方法')

    def process_response(self, request, response):
        print('我是第二个中间件里面的process_response方法')
        return response

    def process_view(self, request, view_func, view_args, view_kwargs):
        print(view_func)
        print(view_args)
        print(view_kwargs)
        print('我是第二个中间件里面的process_view方法')

    def process_exception(self, request, exception):
        print('我是第二个中间件里面的process_exception')

    def process_template_response(self, request, response):
        print('我是第二个中间件里面的process_template_response')
        return response


class MyMdd2(MiddlewareMixin):
    def process_request(self, request):
        print('我是第三个中间件里面的process_request方法')

    def process_response(self, request, response):
        print('我是第三个中间件里面的process_response方法')
        return response

    def process_view(self, request, view_func, view_args, view_kwargs):
        print(view_func)
        print(view_args)
        print(view_kwargs)
        print('我是第三个中间件里面的process_view方法')

    def process_exception(self, request, exception):
        print('我是第三个中间件里面的process_exception')

    def process_template_response(self, request, response):
        print('我是第三个中间件里面的process_template_response')
        return response

The configuration in settings.py

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',
    'mymiddleware.mdd.MyMdd',  # 配置上
    'mymiddleware.mdd.MyMdd1',  # 配置上
    'mymiddleware.mdd.MyMdd2',  # 配置上
]

Methods need to know

process_request

When the request to be executed in the configuration file settings.py registered in the middleware which in turn

  • If the method is not skip, down a middleware
  • If the method returns a HttpResponse object inside, it will turn up execution returns from process_response method from the current middleware, will not be executed then down
  • Execution sequence: from the top
  • The method can be implemented restrictions on user identity verification, access frequency, verify the user permissions ...

You can do to limit access based on the frequency characteristics

process_response

Take the time to respond will be executed in turn settings.py configuration file registered in the middleware method (parameter response must be returned, because the response is to refer back to the front of the data)

  • If the method is not skip, down a middleware
  • The order of execution: from the bottom up
  • This method can help you implement caching mechanism (slow pressure on the server, database)

You need to understand the way

process_view

Match before routing the successful implementation of the view function automatically triggers (from top to bottom execution)

process_exception

When the view being given function , automatically triggers (from bottom to top execution)

process_template_response

HttpResponse object containing the view function returns the attributes render triggered when, or indicate when an object or objects TemplateResponse time will trigger an equivalent method (performed from bottom to top)

def index(request):
    print("我是 index 视图函数")
    def render():
        return HttpRespone('用户最终能够看到的结果')  # ******
    obj = HttpResponse('index')
    obj.render = render  # 返回的 HttpResponse 对象中必须包含 render 属性,才能触发中间件里定义的 process_template_response 方法
    return obj

Emphasize:

When writing middleware, as long as the parameter has response, we must remember to return it, this information is to give the front of Response

csrf middleware CSRF

Phishing sites

Principle: write an identical site, a hidden box, send money to the party as a hidden

Q: How to distinguish the current page request sent by the user at us is not our website to this website's

Prevent ideas

The site will be returned to the user's form form page secretly stuffed a random string

Request comes, will first than random strings are the same, if not directly reject (403 FORBIDDEN)

solution

Put on the page a hidden input box, which put the value is a string, each refresh will update the value inside, so people do not know the site; this value can not be faked

django implementation {% csrf_token %}

The random string has the following characteristics:

  • The same browser each visit is different
  • Definitely not the same in different browsers

post request verification data submitted by csrf

form form

When a form to send post request form, you need to do is to write a piece of code {% csrf_token %}, you do not need a comment csrf middleware

Send ajax

Three ways (a third rear end can be separated from the front)

  1. On the first page write {% csrf_token %}, use the tag to find, to get the input key information into the data in

  2. ajax data value where the direct write {{ csrf_token }}( data:{'username':'jason','csrfmiddlewaretoken':'{{ csrf_token }}'},)

  3. Refer to the official documentation recommends, custom js files in use to the page load the js script to automatically obtain and pass csrf check *****

    • You can place the following code into a js file js
    // js 代码(一般放在 static 文件夹下)
    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);
            }
        }
    });
    • After use to place <script src="{% static 'setjs.js' %}"></script>import on the line
    • This eliminates the need to write in html {% csrf_token %}or write in ajax in {{ csrf_token }}the

csrf decorator related

Other middleware can also follow the following methods to verify or canceled check

Two issues

When the global web site you need to check csrf time (when not commented out csrf middleware), there are a few do not need to check how this process? @csrf_exempt

When you do not check csrf global website (at the time commented csrf middleware), there are a few you need to verify how to deal with?@csrf_protect

Single-function cancel csrf check when uncommented csrf Middleware: csrf_exempt

FBV

from django.views.decorators.csrf import csrf_exempt

# 全局开启时,局部禁用
@csrf_exempt
def index(request):
  pass

CBV

There are two ways, not for a single method is for the global

# CBV比较特殊,不能单独加在某个方法上
# 只能加在类上或dispatch方法上
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt


# @method_decorator(csrf_exempt,name='dispatch')  # 第一种
class Csrf_Token(View):
  @method_decorator(csrf_exempt)  # 第二种
  def dispatch(self,request,*args,**kwargs):
    res = super().dispatch(request,*args,**kwargs)
    return res
  # @method_decorator(csrf_exempt)  # 这里这么写不行!!!
  def get(self,request):
    pass
  def post(self,request):
    pass

Single-function check when turned csrf commented csrf Middleware: csrf_protect

FBV

from django.views.decorators.csrf import csrf_protect


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

CBV need to change to change

There are three ways, either for global, it can be for a single

from django.views.decorators.csrf import csrf_protect

from django.views import View
from django.utils.decorators import method_decorator


# 第一种方式
# @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')

Summary: CSRF decorator only csrf_exempt is a special case, when other decorators to decorate the CBV can have three ways

Auth module

Tip science small point:

  • Replace the result is a method of printing out the "string" to confirm the best type, the object may be rewritten __str__()method
  • django Admin Only superusers can enter
  • The method of using the method Auth module, it is best to have a module Auth
  • Change Password must call .save () to save, otherwise invalid

Django auth using a built-in table to do the login function

auth related methods involved

python3 manage.py createsuperuser  # 命令行下创建超级用户(可以拥有登录 django admin 后台管理的权限)

# 查询用户是否存在
user_obj = auth.authenticate(username=username, password=password)  # 数据库中的密码是密文的(该方法不能只传用户名一个参数),返回值要么是对象,要么是 None

# 记录用户状态
auth.login(request, user_obj)  # 登录,会自动存 session
# 优点:只要执行了这一句话,你就可以在后端任意位置通过 request.user 拿到当前登录的用户对象(未登录会报错,AnonymousUser 匿名用户)

# 获取用户对象
request.user  # 用户登录了直接获取用户对象,用户没登录获取到 AnonymousUser 匿名用户

# 判断当前用户是否登录,未登录(AnonymousUser)会返回 False,其他情况下返回 True
request.user.is_authenticated

# 验证用户密码是否正确
is_right = request.user.check_password(old_password)  # 将获取的用户密码,自动加密,然后去数据库中对比(返回布尔值)

# 修改密码
request.user.set_password(new_password)  # 修改密码
request.user.save()  # 需要保存才能生效

# 注销用户
auth.logout(request)  # 等价于 request.session.flush() (删除了 session
表中记录,浏览器 cookie)


# 登录验证装饰器
from django.contrib.auth.decorators import login_required

# @login_required  # 自动校验当前用户是否登录,如果没有登录,(未传参数的情况下)默认跳转到 django 自带的登录页面(还是 404 ?)
# ------ 局部配置
@login_required(login_url='/login/')
def set_password(request):
    pass

# ------ 全局配置(不用在里面写配置了)
# 在 settings.py 中写
LOGIN_URL = '/login/'


# 注册用户
from django.contrib.auth.models import User  # 这就是那张 auth 表
# 创建普通用户
User.objects.create_user(username=username, password=password)
# 创建超级用户
User.objects.create_superuser(username=username, password=password, email='[email protected]')  # 创建超级用户必须传邮箱
# 不能用 User.objects.create(username=username, password=password)  (这样密码没有加密)

Core code

app01/views.py

from django.shortcuts import render, HttpResponse
from django.contrib import auth


def xxx(request):
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        # 取数据库查询当前用户数据
        # models.User.objects.filter(username=username,password=password).first()
        user_obj = auth.authenticate(username=username, password=password)  # 必须要用 因为数据库中的密码字段是密文的 而你获取的用户输入的是明文
        print(user_obj)
        # print(user_obj)
        # print(user_obj.username)
        # print(user_obj.password)
        # 保存用户状态
        # request.session['user'] = user_obj
        auth.login(request, user_obj)  # 将用户状态记录到session中
        """只要执行了这一句话  你就可以在后端任意位置通过request.user获取到当前用户对象"""
    return render(request, 'xxx.html')


def yyy(request):
    print(request.user)  # 如果没有执行auth.login那么拿到的是匿名用户
    print(request.user.is_authenticated)  # 判断用户是否登录  如果是你们用户会返回False
    # print(request.user.username)
    # print(request.user.password)
    return HttpResponse('yyy')


from django.contrib.auth.decorators import login_required


# 修改用户密码
@login_required  # 自动校验当前用户是否登录  如果没有登录 默认跳转到 一个莫名其妙的登陆页面
def set_password(request):
    if request.method == 'POST':
        old_password = request.POST.get('old_password')
        new_password = request.POST.get('new_password')
        # 先判断原密码是否正确
        is_right = request.user.check_password(old_password)  # 将获取的用户密码 自动加密 然后去数据库中对比当前用户的密码是否一致
        if is_right:
            print(is_right)
            # 修改密码
            request.user.set_password(new_password)
            request.user.save()  # 修改密码的时候 一定要save保存 否则无法生效
    return render(request, 'set_password.html')


@login_required
def logout(request):
    # request.session.flush()
    auth.logout(request)
    return HttpResponse("logout")


from django.contrib.auth.models import User


def register(request):
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        user_obj = User.objects.filter(username=username)
        if not user_obj:
            # 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='[email protected]')  # 创建超级用户
    return render(request, 'register.html')

Custom extensions autor Field

premise:

settings.py add additional configuration

# ... 其他配置
# 告诉 django 不再使用 auth 默认的表  而是使用你自定义的表
AUTH_USER_MODEL = 'app01.Userinfo'  # '应用名.模型表类名'
# ... 其他配置

Two ways

app01/models.py

from django.db import models
from django.contrib.auth.models import AbstractUser


# Create your models here.
# 第一种 使用一对一关系  不考虑


# 第二种方式   使用类的继承
class Userinfo(AbstractUser):
    # 千万不要跟原来表(AbstractUser)中的字段有冲突
    phone = models.BigIntegerField()
    avatar = models.CharField(max_length=32)
    # 别忘了去 settings.py 里配置

Next Steps

Perform a database migration command python3 manage.py makemigrations、python3 manage.py migrate( )

After this, all the auth module functions, all based on the table you have created, rather than using auth_user (those no longer automatically create a table)

Django middleware configuration enables to emulate the function plug-in effects

Django middleware is actually a class of functions can be written as a class, not commented executed

We follow the example of middleware (restframework later to learn design thinking is so), make a notification feature , you can send micro-channel notification, SMS notification, right-notification

Code

Key configuration section (design a lot to learn)

start.py entry file

import notify

notify.send_all('国庆放假了 记住放八天哦')

notify/__init__.py The key code (combination of dynamic knowledge importlib introduced, reflection, etc.)

import settings
import importlib


def send_all(content):
    for path_str in settings.NOTIFY_LIST:  # 1.拿出一个个的字符串   'notify.email.Email'
        module_path, class_name = path_str.rsplit('.', maxsplit=1)  # 2.从右边开始 按照点切一个 ['notify.email', 'Email']
        module = importlib.import_module(module_path)  # from notity import msg/email/wechat
        cls = getattr(module, class_name)  # 利用反射 一切皆对象的思想 从文件中获取属性或者方法 cls = 一个个的类名
        obj = cls()  # 类实例化生成对象
        obj.send(content)  # 对象调方法

settings.py configuration (function can be turned on or off here)

NOTIFY_LIST = [
    'notify.email.Email',
    'notify.msg.Msg',
    # 'notify.wechat.WeChat',  # 注释掉了,这个功能就不执行了
    'notify.qq.QQ',
]

Function extension

Then each function file (split into individual files, play with settings.py pluggable effect), in order to add this functionality directly add files to implement these codes can be

notify/email.py

class Email(object):
    def __init__(self):
        pass  # 发送邮件需要的代码配置

    def send(self, content):
        print('邮件通知:%s' % content)

notify/msg.py

class Msg(object):
    def __init__(self):
        pass  # 发送短信需要的代码配置

    def send(self, content):
        print('短信通知:%s' % content)

notify/qq.py

class QQ(object):
    def __init__(self):
        pass  # 发送qq需要的代码准备

    def send(self, content):
        print('qq通知:%s' % content)

notify/wechat.py

class WeChat(object):
    def __init__(self):
        pass  # 发送微信需要的代码配置

    def send(self, content):
        print('微信通知:%s' % content)
Supplementary: pycharm tips

Want to know the current location of the code to jump into, you can click on the icon in the figure, rapid positioning, can let you know the directory structure (presumably to see right)

Guess you like

Origin www.cnblogs.com/suwanbin/p/11591887.html