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'

猜你喜欢

转载自www.cnblogs.com/Ghostant/p/12194014.html