中间件、Auth认证模块

中间件、Auth认证模块

CVB加装饰器

# 写一个装饰器验证session
from functions import wraps
def login_auth(func)
	@wraps(func)
    def inner(request,*args,**kwargs)
    	if request.session.get('name')
        	return func(request,*args,**kwargs)
        return redirect('/login/')
    return inner

第一种

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

class MyHome(View):
    def dispatch(self,request,*args,**kwargs)
    	super().dispatch(reauest,*args,**kwargs)
    
    @method_decorator(login_auth)
    def get(self,request):
        return HttpResponse('ok')

第二种

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

@method_decorator(login_auth,name='get')  # name参数必须指定
class MyHome(View):
    def dispatch(self,request,*args,**kwargs)
    	super().dispatch(reauest,*args,**kwargs)
    
    
    def get(self,request):
        return HttpResponse('ok')

第三种

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

class MyHome(View):
    @method_decorator(login_auth)  # get和post都会被装饰
    def dispatch(self,request,*args,**kwargs)
    	super().dispatch(reauest,*args,**kwargs)
    
    
    def get(self,request):
        return HttpResponse('ok')

中间件

中间件用于在全局范围内改变Django的输入和输出,需要谨慎使用,使用不当会影响性能

简单来说就是在视图函数执行之前和执行之后都可以做一些额外的操作,可以用来控制用户访问频率,全局登录校验,用户访问白名单,黑名单等

Django默认的三个中间件:

  • Csrf
  • Session
  • Auth

中间件可以定义五个方法

  • process_request(self,request)
  • process_response(self,request,response)
  • process_view(self,request,view_args,view_kwargs)
  • process_template_response(self,request,response)
  • process_exception(self,request,exception)

以上方法的返回值可以是None或一个HTTPResponse对象,如果是None,则继续按照django定义的规则向后继续执行,如果是HTTPResponse对象,则直接将该对象返回给用户

如何定义?

在应用下新建一个文件夹,在文件夹下新建一个py文件,然后在settings配置文件中注册

process_request执行顺序

需要一个参数request,可以对request对象进行一系列的操作,后续也可以在视图函数中通过相同的方式获取值

1.中间件的process_request方法是在执行视图函数之前执行的
2.当配置多个中间件时,会按照MIDDLEWARE中的注册顺序,也就是列表的索引值,从前到后依次执行的
3.不同中间件之间传递的request都是同一个对象

process_response执行顺序

需要两个形参,request和response,response是视图函数返回的HTTPResponse对象(django后台处理后给出的一个具体的视图)

1.中间件的process_response方法是在视图函数之后执行的
2.当配置多个中间件时,会按照MIDDLEWARE的注册顺序倒序执行的
3.不同中间件之间传递的request都是同一个对象

process_view执行顺序

需要四个参数:

  • request:是HTTPResponse对象
  • view_func:是diango即将使用的函数(它是实际的函数对象)
  • view_args:是将传递给函数的位置参数的列表
  • view_kwargs:是将传递给视图函数的关键字参数的字典
1.diango会在路由系统之后,视图函数之前调用process_view方法
2.按照MIDDLEWARE中的注册顺序从前往后顺序执行

process_exception执行顺序

需要两个参数:

  • request:是HTTPResponse对象
  • exception:是视图函数异常产生的Exception对象
1.中间件的process_exception方法是在视图函数之后执行的
2.当配置多个中间件时,会按照MIDDLEWARE的注册顺序倒序执行的

如果视图函数中无异常,该方法不执行

process_template_response(用的比较少)执行顺序

需要两个参数:

  • request:是HTTPResponse对象
  • response:是TemplateResponse对象(由视图函数产生或中间件产生)
在视图函数执行完后立即执行,顺序是倒序,但是有一个条件,那就是视图函数返回的对象有一个render()方法

中间件执行流程总结:

请求到达中间件之后,先按照正序执行每个注册中间件的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方法。

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

process_template_response和process_exception两个方法的触发是有条件的,执行顺序也是倒序

csrf(跨站请求伪造)

form表单中跨站请求伪造

<form method='post'>
    {% csrf_token %}
</form>

ajax中设置csrf_token

将随机产生的字符串放进数据传给后端,键固定,值以属性查找的方式找到

{% csrf_token %}
<button>
    ajax
</button>
<script>
    $('button').click(function){
        $.ajax({
            url:'',
            type:'post',
            data:{'name':'lucas','csrfmiddlewaretoken':$('[name="csrfmiddlewaretoken"]').val()},  //第一种
             data:{'name':'lucas','csrfmiddlewaretoken':'{{ csrf_token }}'},   //第二种
            success:function(data){
                console.log(data)
            }
        })
    }
</script>

csrf_token局部使用

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

# 局部禁用
@csrf_exempt
def index(request):
    pass


# 局部使用
@csrf_procept
def login(request):
    pass


# CBV比较特殊,不能单独加在某个方法上
# 只能加在类上或dispatch方法上

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

注意:csrf_protect 跟正常的CBV装饰器一样 三种

Auth认证模块

auth_user表记录的添加

  • 创建超级用户(不可手动插入,因为密码是加密的)
  • 简单使用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) # 判断用户是否存在
        if user:
            return redirect('/home/')
    return render(request,'login.html')

auth存储session

if user:
    auth.login(request,user)  # 一旦记录了,可以在任意地方通过request.user获取当前登入对象

判断是否登入

def index(request):
    print(request.user.is_authenticated())  # 判断当前用户是否已经登入
    print(request.user,type(request.user))  # 获取当前登入用户对象
    

删除session值

def logout(request):
    auth.logout(request)  # request.session.flush

创建用户

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('当前用户已存在')
        # models.User.objects.create(username=username,password=password)
        # 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@163.com')  # 创建超级用户
    return render(request,'auth_register.html')

修改密码

def auth_password(request):
    print(request.user.password)
    is_res = request.user.check_password('jason123')  # 校验密码是否一致
    if is_res:
        request.user.set_password('666')  # 设置新密码
        request.user.save()  # 修改密码必须save保存  不然无效
    return HttpResponse('ok')

装饰器工具

局部配置

from django.contrib.auth.decorators import login_required

@login_required(login_url='/login/')
def home(request):
    return HttpResponse('ok')

自定义登入的URL

需要在settings文件中修改

# auth自动跳转
LOGIN_URL = '/login/'  # 这里配置项目登入页面的路由,原路径还是要自己判断

扩展默认的auth_user表

通过继承内置的AbstractUser类,来定义一个自己的Model类

既能根据项目需求灵活的设计用户表,又能使用Django强大的认证系统

from django.db import models
from django.contrib.auth.models import User,AbstractUser
# Create your models here.
# 第一种扩展字段的方式(了解即可)
# class Userinfo(models.Model):
#     phone = models.CharField(max_length=32)
#     avatar = models.CharField(max_length=32)
#     ab = models.OneToOneField(to=User)

class Userinfo(AbstractUser):
    phone = models.CharField(max_length=32)
    avatar = models.CharField(max_length=32)

注意:扩展了内置的auth_user表之后,一定要在settings中告诉Django

# AUTH_USER_MODEL = 'app名.models里面对应的模型表名'
AUTH_USER_MODEL = 'app01.Userinfo'

最后补一张请求流程图

posted @ 2019-06-18 21:31  ymg-颜  阅读(316)  评论(0编辑  收藏  举报