Django 之 中间件,auth模块

中间件

中间件是介于request与response处理之间的一道处理过程,相对比较轻量级,并且在全局上改变django的输入与输出,一个中间件组件专注于做一件特定的事。利用Django中间件能够帮我实现 网站全局的身份验证,黑名单,白名单,访问频率限制,反爬相关等。

激活中间件

想激活一个中间件组件,把它添加到 Django 设置文件中的MIDDLEWARE_CLASSES列表里。MIDDLEWARE_CLASSES 设置中的各个中间件组件使用字符串表示,这个字符串是中间件类名的完整 Python 路径。

django默认有七个中间件,但是django暴露给用户可以自定义中间件并且里面可以写五种方法

  • process_request:请求来的时候从上往下依次执行每一个中间件里面的process_request
  • process_response :响应走的时候会从下往上依次执行每一个中间件里面的process_response方法
  • process_view:路由匹配成功执行视图之前自动触发(从上往下依次执行)
  • process_exception:当视图函数报错了,自动触发(从下往上依次执行)
  • process_template_response:视图函数返回的对象有一个render()方法,(或者表明该对象是一个TemplateResponse对象或等价方法)(从下往上依次执行)

process_request

process_request(request)
  • request是一个HttpRequest对象。
  • 处理请求时,Django 在决定执行哪个视图之前调用process_request()。

这个方法应该返回None或一个HttpResponse对象。如果返回None,Django 继续处理请求,调用其他中间件中的process_request()方法,然后调用process_view()方法,最后执行恰当的视图。

如果返回一个HttpResponse对象,Django 不再调用其他处理请求、视图或异常的中间件,也不执行视图,而是应用响应中间件,返回结果。

process_view

process_view(request, view_func, view_args, view_kwargs)
  • request是一个HttpRequest对象。
  • view_func是 Django 将使用的 Python 函数。(是函数对象,而非函数名称的字符串形式。)
  • view_args是要传给视图的位置参数列表。
  • view_kwargs是要传给视图的关键字参数字典。
  • view_args和view_kwargs中都不包含视图的第一个参数(request)。

process_view()方法在 Django 调用视图之前的最后一刻调用,应该返回None或一个HttpResponse对象。如果返回None,Django 将继续处理请求,调用其他中间件中的process_view()方法,然后执行恰当的视图。

如果返回一个HttpResponse对象,Django 不会再调用其他视图或异常中间件,也不执行视图,而是应用响应中间件,返回结果。

process_template_response

process_template_response(request, response)
  • request是一个HttpRequest对象。
  • response是一个TemplateResponse对象(或其他等效的对象),由 Django 视图或中间件返回。

process_template_response()在视图执行完毕后立即调用。如果响应实例有render()方法,表明它是Tem-plateResponse或等效的对象。

process_template_response()方法必须返回一个实现render方法的响应对象。为此,可以修改传入的re-sponse的response.template_name和response.context_data,也可以创建并返回全新的TemplateResponse或等效的对象

扫描二维码关注公众号,回复: 6549224 查看本文章

process_response

process_response(request, response)

  • request是一个HttpRequest对象。
  • response是 Django 视图或中间件返回的HttpResponse或StreamingHttpResponse对象。

所有响应在返回给浏览器之前都会调用process_response()方法。这个方法必须返回一个HttpResponse或StreamingHttpResponse对象。为此,可以修改传入的response,或者创建并返回全新的HttpResponse或StreamingHttpResponse对象。

与process_request()和process_view()方法不同,process_response()方法始终调用,即便跳过了所在中间件类的process_request()和process_view()方法也是如此(因为前面的中间件返回的是HttpResponse对象)。因此,process_response()方法不能依赖process_request()所做的设置。

process_exception

process_exception(request, exception)
  • request是一个HttpRequest对象。
  • exception是一个Exception对象,由视图函数抛出。

Django 在视图抛出异常时调用process_exception()方法。这个方法应该返回None或一个HttpResponse对象。如果返回HttpResponse对象,会应用模板响应和响应中间件,然后把得到的响应返回给浏览器。否则,使用默认的方式处理异常。

中间件的执行流程

请求到达中间件之后,先按照正序执行每个注册中间件的process_request方法,process_request方法返回的值是None,就依次执行,如果返回的值是HttpResponse对象,不再执行后面的process_request方法,而是执行当前对应中间件的process_response方法(注意不是掉头执行所有的process_response方法),将HttpResponse对象返回给浏览器。也就是说:如果MIDDLEWARE中注册了6个中间件,执行过程中,第3个中间件返回了一个HttpResponse对象,那么第4,5,6中间件的process_request和process_response方法都不执行,顺序执行3,2,1中间件的process_response方法。

img

process_request方法都执行完后,匹配路由,找到要执行的视图函数,先不执行视图函数,先执行中间件中的process_view方法,process_view方法返回None,继续按顺序执行,所有process_view方法执行完后执行视图函数。假如中间件3 的process_view方法返回了HttpResponse对象,则4,5,6的process_view以及视图函数都不执行,直接从最后一个中间件,也就是中间件6的process_response方法开始倒序执行。

img

process_template_response和process_exception两个方法的触发是有条件的,执行顺序也是倒序。总结所有的执行流程如下:

img

img

csrf(跨站请求伪造)

钓鱼网站:银行转账的路径,你是否也可以拿到,然后你做一个跟银行一模一样的页面,也超银行的借口提交数据,当用户在钓鱼网站输入对方账户名和转账金额之后,点击发送。其实内部是将对方账户换成了钓鱼网站的造假人员的账户。造成你转账转错账户的情况.

如何区分钓鱼网站和正经网站?在正经网站返回页面的时候,在form表单中偷偷塞一个特殊的字符串,后端记下该页面对应的字符串的值,等用户发post请求来的时候,我先去校验特殊的字符串是否匹配

写法:

  • 模版语法有一个固定的写法{% csrf_token %},必须写在form表单内,浏览器查看改标签的值,并且每次都在刷新。
<form action="/index/" method="post">
	{% csrf_token %}
    <p>username:<input type="text" name="username"></p>
    <p>money:<input type="text" name="money"></p>
    <p>others:<input type="text" name="others"></p>
    <input type="submit">
</form>
  • ajax中如何设置csrf_token。
用jquery查找标签取值组成键值对放入data中即可
$('button').click(function () {
	$.ajax({
            url:'',
            type:'post',
            data:{'csrfmiddlewaretoken':$('[name="csrfmiddlewaretoken"]').val()},
            success:function (data) {
                console.log(data)
            }
        })
    })

csrf_token局部使用

只想给某个视图韩式加上csrf校验
from django.views.decorators.csrf import csrf_exempt,csrf_protect

局部禁用
@csrf_exempt # 不校验csrf
def index(request):
  pass

局部使用
@csrf_protect # 校验csrf
def login(request):
  pass

csrf_protect:跟正常的CBV装饰器一样,有三种装饰的方法。
csrf_exempt :只能有下面两种方式

from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt,csrf_protect

@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

Auth认证模块

开发一个网站的时候,无可避免的需要设计实现网站的用户系统。此时需要实现包括用户注册、用户登录、用户认证、注销、修改密码等功能。Django内置了强大的用户认证系统–auth,它默认使用 auth_user 表来存储用户数据。

  • 创建用户

    创建用户最直接的方式是使用create_user()辅助函数

def auth_register(request):
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        user_obj = auth.authenticate(request,username=username)
        if user_obj:
            return HttpResponse('当前用户已存在')
        User.objects.create_user(username=username,password=password)  # 创建普通用户
        # 类似于models.User.objects.create(username=username,password=password)
        User.objects.create_superuser(username=username,password=password,email='[email protected]')  # 创建超级用户
    return render(request,'auth_register.html')
  • 修改密码

Django 不在用户模型中存储原始(明文)密码,只存储密码的哈希值。

如果想修改用户的密码,有两个选择:
1.在命令行中使用 manage.py changepassword username命令修改用户的密码。这个命令会提示你输入两次密码。如果两次输入的内容匹配,立即修改密码。如果不指定用户名,这个命令会尝试修改与当前系统用户的用户名一致的那个用户的密码。
2.还可以通过编程方式,使用set_password()方法修改

def auth_password(request):
    print(request.user.password)
    is_res = request.user.check_password('123')  # 校验密码是否一致
    if is_res:
        request.user.set_password('666')  # 设置新密码
        request.user.save()  # 修改密码必须save保存 ,不然无效
    return HttpResponse('修改成功!')
  • auth认证
from django.contrib import auth
def login(request):
  if request.method == 'POST':
    name = request.POST.get('name')
    pwd = request.POST.get('pwd')
    user = auth.authenticate(request,username=name,password=pwd)
    # 类似于user=models.User.objects.filter(username=name,password=pwd).first()
    if user:
  		auth.login(request,user)  # 登陆,其实就把用户信息放到session中
        # 类似于request.session['name']=name
      return redirect('/home/')
  return render(request,'login.html')

上面的验证和登陆其实不是它的亮点,亮点在于

只要登陆成功执行了auth.login(request,user),之后在其他任意的视图函数中都通过request.user获取当前登陆用户对象。
当没有执行auth.login,request.user打印出来的是匿名用户。
通过request.user.is_auth判断request.user用户是否通过auth.login登陆。
  • 注销
def auth_logout(request):
    auth.logout(request)  
    # 等价于删除session数据request.session.flush()
    return HttpResponse('ok')
  • 装饰器校验是否登陆及跳转
from django.contrib.auth.decorators import login_required

@login_required(login_url='/login/')  # 没登陆会跳转到login页面,并且后面会拼接上你上一次想访问的页面路径/login/?next=/test/,可以通过参数修改next键名
def my_view(request):
  pass
  • 如果我所有的视图函数都需要装饰并跳转到login页面,那么我需要写好多份
settings.py:
# 可以在配置文件中指定auth校验登陆不合法统一跳转到某个路径
LOGIN_URL = '/login/'  # 既可以局部配置,也可以全局配置

view.py:
from django.contrib.auth.decorators import login_required
@login_required
def index(request):
    return HttpResponse('index必须登录才能访问')

自定义模型表应用auth功能

  • 一对一关联(不推荐)
from django.contrib.auth.model import User

class UserDetail(models.Models):
  phone = models.CharField(max_length=11)
  user = models.OnoToOneField(to=User)
  • 面向对象的继承
models.py:
from django.contrib.auth.models import User,AbstractUser
class UserInfo(AbstractUser):
  phone = models.CharField(max_length=32)

settings.py:
# 需要在配置文件中,指定我不再使用默认的auth_user表而是使用我自己创建的Userinfo表
# 告诉django不再使用默认的auth_user,而使用我们自己定义的表:AUTH_USER_MODEL = "app名.models里面对应的模型表名"
AUTH_USER_MODEL = 'app01.Userinfo'

自定义认证系统默认使用的数据表之后,我们就可以像使用默认的auth_user表那样使用我们的UserInfo表了。库里面也没有auth_user表了,原来auth表的操作方法,现在全部用自定义的表均可实现。

猜你喜欢

转载自blog.csdn.net/linwow/article/details/92799379