Django对中间件的调用思想、csrf中间件详细介绍、Django settings源码剖析、Django的Auth模块

目录

  • 使用Django对中间件的调用思想完成自己的功能

    • 功能要求
    • importlib模块介绍
    • 功能的实现
  • csrf中间件详细介绍
    • 跨站请求伪造
    • Django csrf中间件
      • form表单
      • ajax
      • csrf相关装饰器
      • 在CBV上加csrf装饰器
  • Django settings源码剖析及模仿使用
    • Django settings源码剖析

      • 查看内部配置文件
    • 模仿使用
  • Auth模块
    • auth简介
    • auth模块常用方法
      • 创建用户
      • 校验用户名和密码
      • 保存用户登录状态
      • 判断当前用户是否登录
      • 校验原密码
      • 修改密码
      • 注销
      • 校验用户登录状态装饰器
      • User对象属性(用户登录权限和管理权限)
    • 扩展auth_user表字段
      • 方式一
      • 方式二

使用Django对中间件的调用思想完成自己的功能

中间件的调用只需要在配置文件中添加,如果不使用某个中间件,只需要在配置文件中将对应的字符串注释掉就可以,这种调用执行某一代码的方式是不是很方便呢?下面我们就利用Django对中间件的调用的思想,将自己的功能也实现和中间件一样的调用方式。

功能要求

假设实现的功能:信息的群发,要求我们写好的信息只需要一键发送就可以通过邮件、短信、微信三种方式一起发送出去,如果我们不需要某种通知方式只需要在配置文件中将其注释掉就可以。

importlib模块介绍

动态导入模块importlib,可以按照填入的以点隔开的字符串文件路径获的方式取到对应的文件。使用方法:

module_path = 'notify.msg'
md = importlib.import_module(module_path) #md就是notify文件夹下的msg文件

如果需要获取文件里面定义的函数或者类,可以使用反射的方法(这里将文件当做一个对象,一切皆对象)

cls = getattr(md,cls_name)#将文件名作为对象右面填类的名字就能拿到对应的类

功能的实现

1.建一个群发信息功能的包如下图,将每一张发送信息的方式写在一个独立的文件中。

2.在每一个通知文件中定义对应的通知类如:

class Msg:
    def __init__(self):
        pass

    # 发送信息前的准备

    def send(self, content):
        print(f'Msg通知:{content}')

3.将每一个文件添加到配置文件如下:

NOTIFY_LISTS = [
    'notify.email.Email',
    'notify.msg.Msg',
    'notify.qq.Qq',
    'notify.WeChat.WeChat'
]

4.在init中对类的查找和实例化进行处理

import importlib
import settings
def send_all(content):
    for path in settings.NOTIFY_LISTS:
        module_path,cls_name = path.rsplit('.',maxsplit=1)
        module = importlib.import_module(module_path)
        cls = getattr(module,cls_name)
        obj = cls()
        obj.send(content)
        

5.在start中调用包实现消息群发的功能

import os,sys
from notify import send_all

sys.path.append(os.path.dirname(__file__))

if __name__ == '__main__':
    send_all('现在测试通知')

Email通知:现在测试通知
Msg通知:现在测试通知
QQ通知:现在测试通知
WeChat通知:现在测试通知

至此功能基本实现。

csrf中间件详细介绍

跨站请求伪造

csrf全称Cross-site request forgery(跨站请求伪造), 是一种挟制用户在当前已登录的Web应用程序上执行非本意的操作的攻击方法。跟跨网站脚本(XSS)相比,XSS 利用的是用户对指定网站的信任,CSRF 利用的是网站对用户网页浏览器的信任。

跨站请求伪造最常见的应用如钓鱼网站,钓鱼网站的具体钓鱼方式:钓鱼网站伪造一个和正规网站界面一模一样的网站,然后将转账(支付)功能的的form表单进行修改,当用户登录时提供的是正规网站的登录接口,而用户支付或转账的对方账户是假的,下面隐藏的是预先设定好的账户(input框的name和value),这样用户每次给对方进行转账都会将钱转到预先设定好的账户。如何解决跨站请求伪造呢?

从服务端的角度来解决这个问题的思路就是如果每次服务端都能识别出来向我提交请求的是我自己的页面还是别人的页面,那么钓鱼网站就无法在用户访问服务器的过程中伪装成服务端网页给服务端发送转账请求了。而Django中的中间件就是通过这种思想解决跨站请求伪造的问题的。

Django csrf中间件

当用户访问有Django csrf中间件的服务端时Django csrf中间件会给用户的get请求的页面携带一个随机字符串,当用户发送post请求时会校验用户的随机字符串,如果如果校验不通过则直接报403错误,禁止用户提交post请求。

<input type="hidden" name="csrfmiddlewaretoken" value="rJ47FeK9T55wavvVJGY6UxdM1kTMHhTqotGfaXjXIK8Ahz2Uvs02yR9T8bBn5q2D">

能否提交post请求的通常是form表单和ajax请求,Djangocsrf中间件在两种post请求中的使用方式是不同的,具体使用方法如下:

form表单

我们只需在form表单中添加{% csrf_token %}。

<form action="" method="post">
    {% csrf_token %}
    <p>username:<input type="text" name="username"></p>
    <p>target_account:<input type="text" name="target_user"></p>
    <p>money:<input type="text" name="money"></p>
    <input type="submit">
</form>
<input type="hidden" name="csrfmiddlewaretoken" value="rJ47FeK9T55wavvVJGY6UxdM1kTMHhTqotGfaXjXIK8Ahz2Uvs02yR9T8bBn5q2D">           

ajax

ajax有三种方式添加中间件标签。

方式一

先在页面任意的位置上书写{% csrf_token %},然后在发送ajax请求的时候通过标签查找获取随机字符串添加到data自定义对象即:
data:{‘username‘:‘xxx‘,‘csrfmiddlewaretoken‘:$(‘input[name="csrfmiddlewaretoken"]‘).val()},

方式二

data:{‘username‘:‘xxx‘,‘csrfmiddlewaretoken‘:‘{{ csrf_token }}‘}

方式三(官方提供,建议使用此方法)

新建一个js文件,将下面的代码拷贝进去,在ajax上面导入即可。

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

导入:

<script src="/static/setup.js"></script>

csrf相关装饰器

csrf相关的装饰器可以按照我们的需求给某个视图函数加csrf校验,或者不给某个视图函数加csrf校验。

csrf_exempt

不给某个视图函数加csrf校验

from django.views.decorators.csrf import csrf_exempt
@csrf_exempt  # 不校验 csrf
def index(request):
    return HttpResponse('index')

csrf_protect

给某个视图函数加csrf校验,这里需要在settings文件中将csrf中间件注释掉。

@csrf_protect  # 校验
def login(request):
    return HttpResponse('login')

在CBV上加csrf装饰器

csrf_exempt

只有一种加装饰器的方法,就是先导入method_decorator方法,然后在类中定义dispatch方法然后将其装饰在dispatch方法上面。@method_decorator(csrf_exempt)

# @method_decorator(csrf_exempt,name='post')  # csrf_exempt不支持该方法
@method_decorator(csrf_exempt,name='dispatch')  # csrf_exempt
class MyIndex(views.View):
    # @method_decorator(csrf_exempt)  # 可以
    def dispatch(self, request, *args, **kwargs):
        return super().dispatch(request,*args,**kwargs)
    def get(self,request):
        return render(request,'transfer.html')
    # @method_decorator(csrf_exempt,name='post')  # csrf_exempt不支持该方法
    def post(self,request):
        return HttpResponse('OK')
    # csrf_exempt这个装饰器只能给dispatch装才能生效

csrf_protect

csrf_protect装饰器用普通加装饰器的方法就可以跟普通的装饰器装饰CBV用法一样。

# @method_decorator(csrf_protect,name='post')  # 可以
class MyIndex(views.View):
    @method_decorator(csrf_protect)
    def dispatch(self, request, *args, **kwargs):
        return super().dispatch(request,*args,**kwargs)
    def get(self,request):
        return render(request,'transfer.html')
    # @method_decorator(csrf_protect)  # 可以
    def post(self,request):
        return HttpResponse('OK')

Django settings源码剖析及模仿使用

Django settings源码剖析

Django有两个配置文件,一个是用户可以看到的settings文件,另一个是内部的全局的配置文件,这两个配置文件的执行方式是如果用户配置了就用用户配置的settings文件,如果用户没有配置settings文件就用内部的settings文件。那么这一功能Django是如何实现的呢?一起来看看Django settings的源码。

查看内部配置文件

from django.conf import settings#配置文件实例化出的一个类
from django.conf import global_settings#配置文件

我们进入第一个settings:发现settings使用了单例模式,

进入LazySettings类里面:

进入manage.py查看项目启动时的配置:

再看LazySettings类

 def _setup(self, name=None):
        """
        Load the settings module pointed to by the environment variable. This
        is used the first time we need any settings at all, if the user has not
        previously configured the settings manually.
        """
        settings_module = os.environ.get(ENVIRONMENT_VARIABLE)
        # os.environ是一个全局的大字典,而settings_module获取了key为ENVIRONMENT_VARIABLE的值,从manage.py中可以看出settings_module获取到的就是用户配置文件路径:项目名.settings
        if not settings_module:
            desc = ("setting %s" % name) if name else "settings"
            raise ImproperlyConfigured(
                "Requested %s, but settings are not configured. "
                "You must either define the environment variable %s "
                "or call settings.configure() before accessing settings."
                % (desc, ENVIRONMENT_VARIABLE))

        self._wrapped = Settings(settings_module)
        #settings路径传入了Settings,我们进Settings里面看看。

class Settings(object):
    def __init__(self, settings_module):
        # update this dict from global settings (but only for ALL_CAPS settings)
        for setting in dir(global_settings):#获取全局配置文件中所有变量名
            if setting.isupper():#只获取是大写的变量名,这就是为啥配置文件中所有的变量名都是大写的
                setattr(self, setting, getattr(global_settings, setting))#setattr将获取到global_settings的变量值添加到settings对象自己的属性中

        # store the settings module in case someone later cares
        self.SETTINGS_MODULE = settings_module#项目名.settings

        mod = importlib.import_module(self.SETTINGS_MODULE)
        #导入暴露给用户的配置文件,相当于from 用户名 import settings

        tuple_settings = (
            "INSTALLED_APPS",
            "TEMPLATE_DIRS",
            "LOCALE_PATHS",
        )

     self._explicit_settings = set()
        for setting in dir(mod):#获取用户配置文件中所有的变量名
            if setting.isupper():
                setting_value = getattr(mod, setting)#利用反射取出所有的变量值

                if (setting in tuple_settings and
                        not isinstance(setting_value, (list, tuple))):
                    raise ImproperlyConfigured("The %s setting must be a list or a tuple. " % setting)
                setattr(self, setting, setting_value)#将用户settings的属性和属性值写入settings对象中
                #到这里我们可以看到,实例化出的settings对象先将全局配置文件中的变量名和变量值写入,然后再将用户配置文件的变量名和变量值写入,这样如果用户配置文件配置了对应的变量名和变量值就会替换掉全局的,从而实现了如果用户配置了settings就用用户的,如果用户没有配置,就用全局的配置文件的功能。
                self._explicit_settings.add(setting)

        if not self.SECRET_KEY:
            raise ImproperlyConfigured("The SECRET_KEY setting must not be empty.")
        

模仿使用

模仿使用其实就是模仿用户settings配置文件如果设置了就用用户的,如果没有设置就用内置的这个功能。

我们只需要在全局配置文件包的__init__中写如下代码:

import importlib
from lib.conf import global_settings
import os

class Settings(object):
    def __init__(self):
        for name in dir(global_settings):
            if name.isupper():
                setattr(self,name,getattr(global_settings,name))
        # 获取暴露给用户的配置文件字符串路径
        module_path = os.environ.get('xxx')
        md = importlib.import_module(module_path)  # md = settings
        for name in dir(md):
            if name.isupper():
                k = name
                v = getattr(md,name)
                setattr(self,k,v)

settings = Settings()

Auth模块

auth简介

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

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

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

auth模块常用方法

功能 代码
创建用户 from django.contrib.auth.models import User
User.objects.create_user(username=username,password=password) # 创建普通用户,密码自动加密
User.objects.create_superuser(username=username,password=password,email=‘[email protected]‘) # 创建超级用户
校验用户名和密码 from django.contrib import auth
user_obj = auth.authenticate(request,username=username,password=password)
保存用户登录状态 auth.login(request,user_obj) 只要这句话执行了后面在任意位置 只要你能拿到request你就可以通过request.user获取到当前登录的用户对象
判断当前用户是否登录 request.user.is_authenticated()
校验原密码 request.user.check_password(old_password)返回bool值
修改密码 request.user.set_password(new_password)
request.user.save() 千万不要忘了save
注销 auth.logout(request)
校验用户登录装饰器 from django.contrib.auth.decorators import login_required
局部配置
@login_required(login_url=‘/login/‘)
def index(request):
pass
全局配置
settings配置文件中直接配置
LOGIN_URL = ‘/login/‘
@login_required
def index(request):
pass
如果全局和局部都配置了以局部的为准

创建用户

create_user()

auth 提供的一个创建新用户的方法,需要提供必要参数(username、password)等,用户名和密码是必须提供的。

from django.contrib.auth.models import User
user = User.objects.create_user(username='用户名',password='密码',email='邮箱',...)

校验用户名和密码

提供了用户认证功能,即验证用户名以及密码是否正确,一般需要username 、password两个关键字参数。

如果认证成功(用户名和密码正确有效),便会返回一个 User 对象。

authenticate()会在该 User 对象上设置一个属性来标识后端已经认证了该用户,且该信息在后续的登录过程中是需要的。

user = authenticate(username='usernamer',password='password')

保存用户登录状态

该函数接受一个HttpRequest对象,以及一个经过认证的User对象。

该函数实现一个用户登录的功能。它本质上会在后端为该用户生成相关session数据

from django.contrib.auth import authenticate, login

def my_view(request):
  username = request.POST['username']
  password = request.POST['password']
  user = authenticate(username=username, password=password)
  if user is not None:
    login(request, user)
    # Redirect to a success page.
    ...
  else:
    # Return an 'invalid login' error message.
    ...

判断当前用户是否登录

判断当前用户是否登录(发送的当前请求是否已经登录)

def my_view(request):
  if not request.user.is_authenticated():
    return redirect('%s?next=%s' % (settings.LOGIN_URL, request.path))

校验原密码

auth 提供的一个检查密码是否正确的方法,需要提供当前请求用户的密码。

密码正确返回True,否则返回False。

ok = user.check_password('密码')

修改密码

auth 提供的一个修改密码的方法,接收 要设置的新密码 作为参数。

注意:设置完一定要调用用户对象的save方法!!!

user.set_password(password='')
user.save()

注销

该函数接受一个HttpRequest对象,无返回值。

当调用该函数时,当前请求的session信息会全部清除。该用户即使没有登录,使用该函数也不会报错。

from django.contrib.auth import logout

def logout_view(request):
  logout(request)
  # Redirect to a success page.

校验用户登录状态装饰器

局部登录认证装饰器

@login_required(login_url=‘/login/‘)判断用户是否登录如果没有则直接跳转到登录页面

from django.contrib.auth.decorators import login_required

@login_required
def my_view(request):
  ...

如果需要自定义登录的URL,则需要在settings.py文件中通过LOGIN_URL进行修改。

示例:

LOGIN_URL = '/login/'  # 这里配置成你项目登录页面的路由

全局登录认证装饰器

在settings文件直接配置

LOGIN_URL = '/login/'#如果全局和局部都配置了以局部的为准

User对象属性(用户登录权限和管理权限)

User对象属性:username, password

is_staff : 用户是否拥有网站的管理权限.

is_active : 是否允许用户登录, 设置为 False,可以在不删除用户的前提下禁止用户登录。

扩展auth_user表字段

方式一

思路:再建一张表,使这张表和auth_user表是一对一的关系,这样可以实现对auth_user表字段的增加。

class UserDetail(models.Model):
    phone = models.BigIntegerField()
    user = models.OneToOneField(to='User')

方式二

思路:自定义一个类和原来的auth_user继承同一个基类,然后自定义类中的字段,这里需要说明的是在自定义类之前不能执行数据库迁移命令,定义好才能执行数据库迁移命令。另外,定义好类之后需要在配置文件中添加下面的配置。

#自定义类
from django.contrib.auth.models import AbstractUser
class Userinfo(AbstractUser):
    phone = models.BigIntegerField()
    register_time = models.DateField(auto_now_add=True)

#配置文件中添加
AUTH_USER_MODEL = 'app01.Userinfo'  # 应用名.表名

上面的步骤完成之后,auth模块的功能都可以在你定义的表中使用。

原文地址:https://www.cnblogs.com/ghylpb/p/11992692.html

时间: 2024-10-14 00:40:07

Django对中间件的调用思想、csrf中间件详细介绍、Django settings源码剖析、Django的Auth模块的相关文章

源码剖析Django REST framework的认证方式及自定义认证

源码剖析Django REST framework的认证方式 由Django的CBV模式流程,可以知道在url匹配完成后,会执行自定义的类中的as_view方法. 如果自定义的类中没有定义as_view方法,根据面向对象中类的继承可以知道,则会执行其父类View中的as_view方法 在Django的View的as_view方法中,又会调用dispatch方法. 现在来看看Django restframework的认证流程 Django restframework是基于Django的框架,所以基

源码剖析Django REST framework的请求生命周期

学习Django的时候知道,在Django请求的生命周期中,请求经过WSGI和中间件到达路由,不管是FBV还是CBV都会先执行View视图函数中的dispatch方法 REST framework是基于Django的API框架,REST framework采用的是CBV的请求模式. 所以在一个项目中,使用了REST framework的时候, 请求到达REST framework后,也先执行REST framework中的dispatch方法 先来看看dispatch方法的源码 def disp

Django的settings源码分析

首先需要在settings文件中导入,然后查看settings源码 from django.conf import global_settings,settings 点进去LazySettings我们会发现它是一个类,所以settings是类实例化出来的对象,这里利用了单例模式. 然后我们点入manage.py文件中看到 最后点入Settings类 原文地址:https://www.cnblogs.com/baohanblog/p/12164257.html

django 之csrf、auth模块及settings源码、插拔式设计

目录 基于django中间件拷贝思想 跨站请求伪造简介 跨站请求伪造解决思路 方式1:form表单发post请求解决方法 方式2:ajax发post请求解决方法 csrf相关的两个装饰器 csrf装饰器在CBV上的特例 django settings源码 auth模块简介 auth创建用户 auth扩展表 基于django settings配置文件实现插拔式设计 csrf:Cross Site Request Forgery protection 基于django中间件拷贝思想 # start.

django restfulwork 源码剖析

概要: 1.restful 规范(建议); 2. django rest framework框架 内容回顾: 1.开发模式; - 普通开发模式(前后端放在一起写) - 前后端分离 好处: 后端一套,前端使用app,pc等: 2. 后端开发 为前端提供URL(API的开发) 注:永远返回Httpresponse 3. django Fbv 和Cbv 一.Django CBV和FBV 在视图中,cbv支持四中method,如下: from django.views import View class

Django Rest Framework源码剖析(三)-----频率控制

一.简介 承接上篇文章Django Rest Framework源码剖析(二)-----权限,当服务的接口被频繁调用,导致资源紧张怎么办呢?当然或许有很多解决办法,比如:负载均衡.提高服务器配置.通过代理限制访问频率等,但是django rest framework自身就提供了访问频率的控制,可以从代码本身做控制. 二.频率控制内部原理概述 django rest framework 中频率控制基本原理基于访问次数和时间,通过计算实现,当然我们也可以自己定义频率控制方法.基本原理如下: 启用频率

Django Rest Framework源码剖析(八)-----视图与路由

一.简介 django rest framework 给我们带来了很多组件,除了认证.权限.序列化...其中一个重要组件就是视图,一般视图是和路由配合使用,这种方式给我们提供了更灵活的使用方法,对于使用者而言不同的视图具有不同的功能,这样我们可以根据需求定制自己视图.以下是官网传送门:http://www.django-rest-framework.org/api-guide/views/ 在之前的文章中,由于参杂了权限.认证等(如果不了解请看博客的以前的文章),但在本章中基本可以不使用,所进使

扫雷源码剖析(设计思想与实现)

转自:http://www.manongjc.com/article/23738.html 引言:在GitHub上面下载了一个扫雷的源程序,不过只有代码,没有注释和详细说明.以前从来也没玩扫雷,通过这次的学习顺便也弄懂了扫雷的玩法.下面附上github的源码地址:https://github.com/lxf44944/minesweeper_java. 一.扫雷的总体设计思想 首先给还不知道的朋友介绍一下它的玩法,此次就以初级难度为例.首先,当你开始运行游戏的时候它是没地雷的,当你鼠标左键第一次

Django的View(视图)、settings源码的解析、模板层

一.FBV与CBV 视图函数并不只是指函数,也可以是类 FBV:基于函数的视图,类似面向函数式编程 CBV:基于类的视图,类似面向对象编程 研究解析render源码: render:返回html页面:并且能够给该页面传值 分析:FBV视图原理 from django.shortcuts import render,HttpResponse # Create your views here. from django.template import Template,Context # FBV解析