django框架之中间件 Auth模块

CBV加装饰器

方式一:装饰器加到想装饰的方法上

方式二:装饰器加到class前面,通过name参数指定被装饰的方法

方式三:重写dispatch(django分发CBV视图函数),直接给dispatch装饰,该类中所有对象方法都将被装饰 

from django.shortcuts import render, HttpResponse, redirect
from django.views import View
from functools import wraps
from django.utils.decorators import method_decorator


def login(request):
    if request.method == 'POST':
        name = request.POST.get('name')
        pwd = request.POST.get('pwd')
        if name == 'Tom' and pwd == '123':
            request.session['name'] = 'Tom'
            return redirect('/home/')
    return render(request, 'login.html')


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


# @method_decorator(login_auth, name='get')  # 第二种,name参数必须指定
class MyHome(View):

    @method_decorator(login_auth)  # 第三种,拦截django分发视图函数的过程
    def dispatch(self, request, *args, **kwargs):
        super().dispatch(request, *args, **kwargs)
# @method_decorator(login_auth) # 第一种 def get(self, request): return HttpResponse('get') def post(self, request): return HttpResponse('post')

 

中间件

处理Django的请求和响应的框架级别的钩子,相当于django的门户;
用于在全局范围内改变Django的输入和输出的插件系统,
本质上就是一个自定义类,Django框架会在请求的特定的时间去执行这些方法。

django中间件可以实现网站全局相关的功能校验:身份验证(RBAC基于角色的权限管理),黑白名单、访问频率限制、反爬相关....
中间件在settings.py的MIDDLEWARE配置列表参数:'应用名.文件夹名.文件名.类名'

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默认7个中间件,给用户提供五个自定义中间件的方法:

process_request(self,request)  

process_view(self, request, view_func, view_args, view_kwargs)

process_template_response(self,request,response)

process_exception(self, request, exception)

process_response(self, request, response)  

 

1)process_request 请求时触发,从上往下依次执行,没有该方法则直接通过 ******

返回值None:继续往后执行;

返回HttpResponse对象:将从同级别process_response返回该对象给浏览器

2)process_view 路由匹配成功,执行视图函数之前触发,从上往下依次执行

返回值None:继续往后执行;

返回HttpResponse对象:将从下往上依次执行每个process_response,返回该对象给浏览器

3)process_exception 视图函数报错时自动触发,从下往上依次执行

4)process_template_response 视图函数返回的对象有一个render()方法时触发(或表明该对象是TemplateResponse对象或等价方法)

  从下往上依次执行,中间报错无返回函数,不会执行

5)process_response 响应时触发,从下往上依次执行 ******

必须将response形参接收的数据返回,不然直接报错

自定义中间件

1. 新建一个文件夹,放入自定义中间件.py文件

2. 导模块导入MiddlewareMixin

3. 自定义继承MiddlewareMixin的类(中间件)

4. 将自定义中间件路径在settings.py文件中的 MIDDLEWARE列表 注册

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse


class MyMiddleWare(MiddlewareMixin):
    def process_request(self, request):
        print('process_request 自定义No.1 方法')
        # return HttpResponse('haha')

    def process_response(self, request, response):
        print('process_response 自定义No.1 方法')
        return response

    def process_view(self, request, view_func, view_args, view_kwargs):
        print('process_view 自定义No.1 方法')
        print(view_func.__name__, view_func)
        return HttpResponse('**************')

    def process_exception(self, request, exception):
        print('process_exception 自定义No.1 方法')
        print(exception)

    def process_template_response(self, request, response):
        print('process_template_response 自定义No.1 方法')
        return response


class MyMiddleWare1(MiddlewareMixin):
    def process_request(self, request):
        print('process_request 自定义 No.2 方法')
        # return HttpResponse('xixi')

    def process_response(self, request, response):
        print('process_response 自定义No.2 方法')
        return response

    def process_view(self, request, view_func, view_args, view_kwargs):
        print('process_view 自定义No.2 方法')
        print(view_func.__name__, view_func)

    def process_exception(self, request, exception):
        print('process_exception 自定义No.2 方法')
        print(exception)

    def process_template_response(self, request, response):
        print('process_template_response 自定义No.2 方法')
        return response
from django.shortcuts import HttpResponse


def index0(request):
    print('我是视图函数index')
    # jhgyuy
    return HttpResponse('index')


def index(request):
    print('我是视图函数index')

    def render():
        print("in index/render")
        return HttpResponse("564K")
    rep = HttpResponse("OK")
    rep.render = render
    # jkgjlie
    return rep
    'app01.mymiddle.ware.MyMiddleWare',
    'app01.mymiddle.ware.MyMiddleWare1',

Csrf 跨站请求伪造

模拟钓鱼网站过程

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')
<h1>正常网站</h1>
<form action="" method="post">
    <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>
<h1>钓鱼网站</h1>
<form action="" 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="Tom" style="display:none">
    <input type="text">
</form>

钓鱼网站和正常网站页面完全一样(路径有别),在钓鱼网站中,第三个others参数另一方账户无法正常输入,

但提交的数据最终提交到正常网站,操作成功,但转账将将转到别的账户,这样,网站存在很大的风险.......

 

django框架通过中间件 'django.middleware.csrf.CsrfViewMiddleware',可以动态生成一条随机数据,每刷新一次页面重新生成,将该数据附在提交数据中,若该数据不存在,或者和该网站内部的数据无法匹配上,即拒绝执行后续操作。如何在post请求中携带该数据?可将该该数据隐藏于一个标签:

1. form表单跨站请求伪造:

{% csrf_token %}

2. Ajax跨站请求伪造,data中加入该键值对:

'csrfmiddlewaretoken': $('[name="csrfmiddlewaretoken"]').val()

or

'csrfmiddlewaretoken':'{{ csrf_token }}'

 

页面数据:<input type="hidden" name="csrfmiddlewaretoken" value="CWg1rnImJfBiJrdVV6iGORUQQHrIAkWJn3nU3VdFnJmNXx8FTac1UZk2eIsQa6Cz"

<h1>正常网站</h1>
<form action="" 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>
{% csrf_token %}

<button>ajax</button>

<script>
    $('button').click(function () {
        $.ajax({
            url:'',
            type:'post',
            data:{'name': 'jason','csrfmiddlewaretoken': $('[name="csrfmiddlewaretoken"]').val()},

            succecc:function (data) {
                console.log(data)
            }
        })
    })
</script>

单独配置csrf校验

全局校验csrf时,某个视图函数不需要校验;全局不校验时,某个视图函数需要校验?

1.FBV的csrf校验

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


@csrf_exempt  # 不校验csrf
def exempt(request):
    return HttpResponse('exempt')


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

2. CBV的csrf校验

csrf_protect 校验:和正常的CBV装饰器一样,三种

# @method_decorator(csrf_protect, name='post')  # 第一种
class index2(View):
    @method_decorator(csrf_protect)
    def dispatch(self, request, *args, **kwargs):  # 第三种
        super().dispatch(request, *args, **kwargs)

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

    # @method_decorator(csrf_protect)  # 第二种
    def post(self, request):
        return HttpResponse('post')

csrf_exempt校验:不能单独给一个方法加校验,只能配置到一个路由下,两种

@method_decorator(csrf_exempt, name='dispatch')  # 第一种
class index1(View):
    # @method_decorator(csrf_exempt)  # 第二种
    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')

 

Auth模块

django自带的用户功能模块

常用语句:

auth.authenticate(request, **kwargs)    查询用户

   .login(request, user_obj)        记录用户登录状态,任何地方request.user获取登录对象

   .logout(request)            退出登录

 

User.objects.create(**kwargs)         新建用户,密码是明文

 .create_user(**kwargs)     新建用户,普通用户

 .create_superuser(**kwargs)  新建vip,必须有Email,具有Django后台管理登录权限

命令:python3 manage.py createsuperuser     创建超级用户:vip

 

request.user                 获取当前登录对象

 .is_authenticated()          是否登录

 .password             查询密码

 .check_password('num')      核对密码是否正确

 .set_password('num')        修改密码

 .save()              保存修改    

 

登录

from django.contrib import auth


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'] = 'jason'
            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('index')


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

注册

from django.contrib.auth.models import 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(username=username, password=password)  # 密码是明文
        # User.objects.create_user(username=username, password=password)  # 普通用户
        User.objects.create_superuser(username=username, password=password, email='123@qq.com')  # vip,必须有Email
    return render(request, 'auth_register.html')

修改密码

def auth_password(request):
    print(request.user.password)  # 拿到密码(密文)
    is_true = request.user.check_password('123')  # 核对密码
    if is_true:
        request.user.set_password('321')  # 修改密码
        request.user.save()  # 保存修改

    return HttpResponse('change ok')

登录验证

auth模块提供登录验证功能,需导入login_required

from django.contrib.auth.decorators import login_required


# 局部登录验证
@login_required(login_url='/auth_login/')  # 默认跳转登录'/login/',路径不同则需指定
def auth_home(request):
    return HttpResponse('必须登录才能访问')

所有视图函数都需要登录验证,可以在settings.py设置全局登录参数配置

# auth 没有登录,则自动跳转登录页面
LOGIN_URL = '/auth_login/'

Auth模块自定义表

1. 导入模块中的数据:User, AbstractUser

2. 在settings.py中配置好参数,使用自定义的表名

AUTH_USER_MODEL = 'app名.models对应的模型表名'

3. 在使用Auth模块的的常用语句时,使用自定义类名即可

models.py

from django.db import models
from django.contrib.auth.models import User, AbstractUser


class UserInfo(models.Model):  # 第一种:一对一关联表(了解)
    phone = models.CharField(max_length=32)
    avatar = models.CharField(max_length=32)
    ab = models.OneToOneField(to=User)


class Userinfo(AbstractUser):   # 第二种:面向对象的继承AbstractUser
    phone = models.CharField(max_length=32)
    avatar = models.CharField(max_length=32)

settings.py

# 告诉django不在使用默认的auth_user,使用自定义的表
AUTH_USER_MODEL = 'app01.Userinfo'

 

posted @ 2019-06-18 23:06  zhoyong  阅读(238)  评论(0编辑  收藏  举报