Django之中间件和Auth模块

CBV装饰器

写一个装饰器在session上

def login_auth(func):
  def inner(request,*args,**kwargs):
    if request.session.get('is_login'):
      return func(request,*args,**kwargs)
       else:
      return redirect('/login/')
    return inner

三种方法:

第一种就是直接在里面给方法加上装饰器,方法上面加,不要用原生的装饰器,用的话,只能改参数,那样的话不通用

第二种就是在类的上面加装饰器,name=‘方法’指向该方法

from django.utils.decoration import method_decorator
#
@method_decorator(login_auth,name='get') # 第二种 name参数必须指定 class MyHome(View):
  # @method_decorator(login_auth) # 第一种 def get(self,request): return HttpResponse('get') def post(self,request): return HttpResponse('post')

第三种:利用dispatch来装饰所有的方法

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

        def post(self,request):
            return HttpResponse('post')

中间件

那么,我们还是先来看一下Django的请求生命周期

从上面的图中我们可以发现,中间件在这其中起到了很重要的作用。

它是一个轻量、低级别的插件系统,用于在全局范围内改变Django的输入和输出。每个中间件组件都负责做一些特定的功能。

在settings文件里面就有这样的中间件配置


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

1.请求来的时候会依次执行每一个中间件里面的process_request方法(如果没有直接通过)
2.响应走的时候会依次执行每一个中间件里面的process_response方法(如果没有直接通过)

django中间件能够帮我实现 网站全局的身份验证,黑名单,白名单,访问频率限制,反爬相关
》》》:django用来帮你全局相关的功能校验

自定义中间件
新建一个任意名字的文件夹,里面新建一个任意名字py文件

from django.utils.deprecation import MiddlewareMixin

插件类:

process_request:请求来的时候从上往下依次执行每一个中间件里面的process_request


process_response :响应走的时候会从下往上依次执行每一个中间件里面的process_response方法


process_view:路由匹配成功执行视图之前自动触发(从上往下依次执行)


process_exception:当视图函数报错了,自动触发(从下往上依次执行)


process_template_response:视图函数返回的对象有一个render()方法

(或者表明该对象是一个TemplateResponse对象或等价方法)(从下往上依次执行)

自定义中间件

from django.utils.deprecation import MiddlewareMixin


class MyMiddleWare(MiddlewareMixin):
    def process_request(self, request):
        print('我是第一个自定义的中间件的process_request!')
# 写一个路由与视图,启动项目,查看打印结果。
# 再写一个自定义中间件

class MyMiddleWare(MiddlewareMixin):
    def process_request(self, request):
        print('我是第二个自定义的中间件的process_request!')
# 诠释中间件的执行顺序


# 在两个中间件中添加process_response方法。研究中间件消息进出的顺序
class MyMiddleWare(MiddlewareMixin):
    def process_request(self, request):
        print('我是第一个自定义的中间件的process_request!')
    def process_response(self,request,response):
          print('我是第一个自定义的中间件的process_response')
        return response
# 再来研究process_request中直接返回HttpReponse对象,会怎么走接下来的process_response

# process_view,process_exception,process_template_response

csrf(跨站请求伪造)

先写一个简单的post请求,复现报错信息

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

开两个django项目,模拟转账的现象

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

如何去写这个特殊的字符串呢?模版语法有一个固定的写法{% csrf_token %},必须写在form表单内

浏览器查看改标签的值,并且每次都在刷新。再来演示刚刚转账的示例

ajax中如何设置csrf_token

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

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

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

转账钓鱼案例

def transfer(request):
    if request.method == 'POST':
        username = request.POST.get("username")
        money = request.POST.get('money')
        others = request.POST.get('others')
        print('%s 给 %s 转了 %s'%(username,others,money))
    return render(request,'transfer.html')
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
    <link rel="stylesheet" href="/static/bootstrap-3.3.7/css/bootstrap.min.css">
    <script src="/static/bootstrap-3.3.7/js/bootstrap.min.js"></script>
</head>
<body>
<h1>正经的网站</h1>
<form action="/index3/" 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>
<button>ajax</button>
<script>
    $('button').click(function () {
        $.ajax({
            url:'',
            type:'post',
            data:{'name':'khan','csrfmiddlewaretoken':$('[name="csrfmiddlewaretoken"]').val()},
            success:function (data) {
                console.log(data)
            }
        })
    })

</script>

</body>
</html>

另起一个项目,钓鱼页面与原始页面类似

通过像原网站发送请求,钓鱼网站的一个input框就用户替换了,这时候钱自然就流向了非法分子,有了{% csrf_token %},那么服务端就不在接受钓鱼网站的post请求

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
    <link rel="stylesheet" href="/static/bootstrap-3.3.7/css/bootstrap.min.css">
    <script src="/static/bootstrap-3.3.7/js/bootstrap.min.js"></script>
</head>
<body>
<h1>钓鱼网站</h1>
<form action="http://127.0.0.1:8000/transfer/" method="post">
    <p>username:<input type="text" name="username"></p>
    <p>money:<input type="text" name="money"></p>
    <p>others:<input type="text"></p>
    <input type="text" name="others" value="khan" style="display:none">
    <input type="submit">
</form>
</body>
</html>

 

Auth认证模块

 执行数据库迁移的那两条命令时,即使我们没有建表,也会出现autho_user表,我们一起来看一下怎么操作该表。

from django.contrib import auth
from django.contrib.auth.models import User
def auth_login(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(request,username=username,password=password)
        if user_obj:
            # 记录用户状态
            # request.session['name'] = 'khan'
            auth.login(request,user_obj)  # 一旦记录了,可以在任意的地方通过request.user获取到当前登录对象
            return HttpResponse('ok')

    return render(request,'auth_login.html')


def auth_index(request):
    print(request.user.is_authenticated())  # 判断当前用户是否已经登录
    print(request.user,type(request.user))  # 获取当前登录用户对象
    return HttpResponse('ok')


def auth_logout(request):
    auth.logout(request)  # request.session.flush()
    return HttpResponse('ok')


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('khan123')  # 校验密码是否一致
    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/',redirect_field_name='old') 
# 没登陆会跳转到login页面,并且后面会拼接上你上一次想访问的页面路径/login/?next=/test/,可以通过参数修改next键名 def my_view(request): pass

如果我所有的视图函数都需要装饰并跳转到login页面,那么我需要写好多份。

其实可以去settings里面去配置

# 可以在配置文件中指定auth校验登陆不合法统一跳转到某个路径
LOGIN_URL = '/login/'  # 既可以局部配置,也可以全局配置

自定义模型表应用auth功能

第一种:可以建立一对一关系的模型表

from django.contrib.auth.model import User

class UserDetail(models.Models):
  phone = models.CharField(max_length=11)
  user = models.OnoToOneField(to=User)

第二种:面向对象继承

from django.contrib.auth.models import User,AbstractUser
class UserInfo(AbstractUser):
  phone = models.CharField(max_length=32)

# 需要在配置文件中,指定我不再使用默认的auth_user表而是使用我自己创建的Userinfo表
AUTH_USER_MODEL = "app名.models里面对应的模型表名"
承蒙关照
原文地址:https://www.cnblogs.com/guanlei/p/11048291.html