FRI.Django 中的装饰器及 Auth 模块

FRI.Django 中的装饰器及 Auth 模块

CBV 装饰器

添加装饰器的三种方式

No.1 Scheme  指名道姓
from django.views import View
from django.utils.decorators import method_decorator


class MyLogin(View):
    @method_decorator(login_property)
    def get(self, request):
        return HttpResponse('get 请求')
      
      
No.2 Scheme
@method_decorator(login_property, name='get')  # 可以添加多个,针对不同的方法添加不同的装饰器
class MyLogin(View):
    def get(self, request):
        return HttpResponse('get 请求')
      
      
No.3 Scheme
class MyLogin(View):
    @method_decorator(login_property)  # 它会直接作用于当前类里面的所有方法
    def dispatch(self, request, *args, **kwargs):
        pass

Django 中间件

Django中间件是 Django 的门户
1、请求来的时候需要经过中间件才能到达真正的 Django 后端
2、响应走的时候最后也需要经过中间件才能发送出去

Django 生命周期流程图

研究 Django 中间件代码规律

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',  # --> from django.contrib.sessions.middleware import SessionMiddleware 即路径的字符串形式,本质上是 '路径' + '模块/类'
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',  # 认证相关
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

自定义中间件

1、在项目名或者应用名下建一个文件夹
2、在文件中建一个 py 文件
3、写一个类,必须继承 MiddlewareMixin
4、将类的路径以字符串的形式注册到配置文件中才能生效


'''
Django 支持程序员自定义中间件并且暴露给程序员可以自定义的方法
	掌握
		- prpcess_request
				-- 请求来的时候需要经过每一个中间件里面的 prpcess_request 方法
				-- 在 Pycharm 中打印顺顺是按照配置文件中注册的中间件从上往下的顺序依次执行
				-- 如果中间件里面没有定义该方法,则直接跳过
				-- 如果该方法返回了 HttpResponse 对象,那么请求将不再继续往后执行,而是直接原路返回
				
		该方法用来做全局相关的限制功能
				
		- process_response
				-- 响应走的时候需要结果每一个中间件里面的 process_response
				-- 该方法必须返回一个 HttpResponse 对象
						· 默认返回的就是形参 response
						· 也可以自己返回自己的
				-- 顺序是按照配置文件中注册了的中间件自下而上依次经过,如果没有定义的话,直接跳过执行下一个
'''
      
'''
	了解
		- process_view
				-- 路由匹配成功之后,执行视图函数之前,会自动执行中间件里面的该方法
				-- 顺序是按照配置文件中注册的中间件从上往下顺序依次执行
				
		- process_template_response
				-- 返回的 HttpResponse 对象有 render 属性的时候才会触发
				-- 顺序是按照配置文件中注册的中间件从下往上依次执行
			
		- process_exception
				-- 当视图函数出现异常的情况下触发
				-- 顺序是按照配置文件中注册了的中间件从上往下依次执行
'''

中间件执行顺序

process_request => 自上而下
process_request => 自下而上

'''
思考
   如果在第一个 process_request 方法已经返回了 HttpResponse 对象,那么响应走的时候是经过所有的中间件里面的 process_response 还是直接返回?
		直接通过同级别的 process_response 返回
'''

补充:
		flask 框架也有一个中间件,但是两者略有差异
  	只要有数据返回,就必须经过所有中间件里面的类似于 process_response 方法

CSRF 跨站请求

'''
使用 csrf 跨站请求伪造校验防止钓鱼网站
	网站在给用户返回一个具有提交数据功能页面的时候会给这个页面加一个唯一标识
	当这个页面超后端发送 post 请求的时候,后端会先校验唯一表示,如果标识不合法会直接拒绝,如果合法则正常执行
'''

如何符合校验

form 表单提交符合校验
<form action="" method="post">
    {% csrf_token %}
  <p>username:<input type="text" name="username"></p>
  <p>target_user:<input type="text" name="target_user"></p>
  <p>money:<input type="text" name="money"></p>
  <input type="submit">
</form>


Ajax 请求
3、引用自定义 js 文件
<script>
    $('#btn').click(function () {
        $.ajax({
            url:'',  
            type:'post', 
            data:{"username": 'Jhin', "csrfmiddlewaretoken": $('[name=csrfmidllewaretoken]').val()},  // 1、利用标签查找获取页面上的随机字符串
						{"username": 'Jhin', "csrfmiddlewaretoken": '{{ csrf_token }}'}  // 2、利用末班语法提供的快结束写
          success:function (data) {
                $('#d3').val(data)
            }
        })
    })

</script>

CSRF装饰器

为什么要用装饰器

  • 对所有函数进行按需分配,对不需要验证 CSRF 的函数添加 csrf_exempt,对需要验证 CSRF 的函数添加 csrf_protect
csrf_protect -- 需要校验
csrf_exempt -- 忽略校验

FBV 使用 CSRF 装饰器

@csrf_protect/csrf_exempt
def login(request):
    if request.method == 'POST':
        account = request.POST.get('account')
        password = request.POST.get('password')
        if account == 'Only' and password == '0310':
            last_url = request.GET.get('next')
            if last_url:
                obj = redirect(last_url)
            # 保存用户登录状态
            else:
                obj = redirect('/model/')
            obj.set_cookie('account', 'Just_you', max_age=20000)
            return obj
    return render(request, 'login.html')

CBV 使用 CSRF 装饰器

  • csrf_protect
No.1 Scheme
class MyCsrfToken(View):
    @method_decorator(csrf_protect)
    def k2(self,request):
        return HttpResponse('收到了宝贝')
    
    @method_decorator(csrf_exempt)
    def f1(self, request):
        return HttpResponse('滚犊子')
 

No.2 Scheme
@method_decorator(csrf_protect, name='k2')
class MyCsrfToken(View):
    def k2(self, request):
        return HttpResponse('收到了宝贝')

    def f1(self, request):
        return HttpResponse('滚犊子')
      
      
No.3 Scheme
class MyCsrfToken(View):
    @method_decorator(csrf_protect)
    def dispatch(self, request, *args, **kwargs):
        return super(MyCsrfToken, self).dispatch(request, *args, **kwargs)
  • csrf_exempt
class MyCsrfToken(View):
    @method_decorator(csrf_exempt)
    def dispatch(self, request, *args, **kwargs):
        return super(MyCsrfToken, self).dispatch(request, *args, **kwargs)

Auth 模块

'''
其实在创建号 Django 项目之后直接执行数据库迁移命令会自动生成 auth_user
Django 在启动之后就可以直接访问 admin 路由,需要输入用户名和密码,数据参考的就是 auth_user 表,并且必须是管理员用户才能进入
'''

创建超级用户

python3 manage.py create superuser
依赖于 auth_user 表完成用户相关所有功能
from django.contrib import auth
from django.contrib.auth.decorators import login_required


def home(request):
    if request.user.is_authenticated():
        return redirect('/beauty/')
    return redirect('/beauty/login/')
  

def register(request):
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')

        # 创建普通用户
        # User.objects.create_user(username=username, password=password)
        # 创建超级用户: 使用代码创建超级用户, 必须指定邮箱, 用命令行则可以忽略
        User.objects.create_superuser(username=username, email='Roger@that.com', password=password)
    return render(request, 'register.html')
  
  
def login(request):
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')

        # 使用 auth 模块获取表中数据, 并校验, 得到结果为用户对象
        user_obj = auth.authenticate(request, username=username, password=password)
        """
        1.自动查找 auth_user 表
        2.自动给密码加密并比对
        注意: 必须同时传入用户名和密码
        """

        if user_obj:
            # 保存用户状态, 且只要执行了该方法,就可以在任意位置通过 request.user 获取到当前登录的用户对象
            auth.login(request, user_obj)
    return render(request, 'login.html')


@login_required(login_url='/beauty/login/')  # 局部配置: 用户没有登录则跳转到 login_url 指定的地址
def set_pwd(request):
    if request.method == 'POST':
        raw_password = request.POST.get('raw_password')
        new_password = request.POST.get('new_password')
        confirm_password = request.POST.get('confirm_password')

        # 校验原密码是否正确
        is_right = request.user.check_password(raw_password)
        if is_right:

            # 校验输入的两次新密码是否相同
            if new_password == confirm_password:

                # 修改并保存密码
                request.user.set_password(confirm_password)  # 仅仅修改对象属性
                request.user.save()  # 操作数据库修改密码
                return redirect('/beauty/')
    return render(request, 'set_pwd.html', locals())

Auth_User 表扩展

1、一对一表关系,建立外键(不推荐)
class UserDetail(models.Model):
    phone = models.BigIntegerField()
    user = models.OneToOneField(to='User')

    
2、面向是对象继承
class UserInfo(AbstractUser):
    phone = models.BigIntegerField()

   
'''
注意:
如果继承了 AbstractUser
那么在执行数据库迁移命令的时候 auth_user 表便不再被创建
而 UserInfo 表则会取代 auth_user 表并添加自定义字段
这能更加方便、快捷地完成表的操作及扩展

前提:
    1、在继承之前不能执行过数据库迁移命令
        继承要发生在 auth_user 表创建之前, 若 auth_user 表已创建, 则需要换一个库
    2、继承的类里面不要覆盖 AbstractUser 自带的字段名
        只要在原字段的基础上添加之外的字段名即可
    3、需要在配置文件中声明使用 UserInfo 替代 auth_user
        AUTH_USER_MODEL = '应用名.UserInfo'
'''

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值