Django-(10)

内容概览

  • csrf跨站请求伪造
  • csrf预防操作
  • csrf相关装饰器
  • auth认证模块
  • auth_user表切换
  • 基于django中间件设计项目功能

csrf跨站请求伪造

  1. 简介
    CSRF(Cross-site request forgery)跨站请求伪造,是一种对网站的恶意利用;主要是因为网站的cookie会保存在浏览器中,在有效期中,可以通过一些手段执行用户不想做的功能
  2. 模拟
    创建两个一模一样的网页,一个为真一个为假;在计算机上两个服务端不同端口启动,钓鱼网页提交地址改为真网页的地址
    真:
    <form action="" method="post">
    <p>用户:<input type="text" name="username"></p>   转账人
    <p>目标用户:<input type="text" name="target_name"></p>		收款人
    <p>转账金额:<input type="text" name="money"></p>	转账金额
    <input type="submit">
    </form>
    
    假:
    <form action="http://127.0.0.1:8000/login/" method="post">    直接给真网站发送请求
    <p>用户:<input type="text" name="username"></p>
    <p>目标用户:<input type="text"></p>	不设置name属性,使这一标签没有实际作用
    <input type="text" name="target_name" value="xxx" style="display: none">	自己设定收款人,并将标签隐藏
    <p>转账金额:<input type="text" name="money"></p>
    <input type="submit">
    </form>
    
    如果使用钓鱼网站转账,那么永远只会给xxx转账
  3. 预防
    csrf策略:通过给返回的页面添加一个独一无二的标识信息从而区分正规网站和钓鱼网站的请求

csrf预防操作

之前一直注释掉的中间件,就是用来发送标识信息的
将其注释了代表任意页面都能够直接发送post请求
启用后再发送post请求需要添加模板语法

1. form表单
	<form action="" method="post">
		{% csrf_token %}    <!--通过检查可以看到模板语法添加了一个input标签:<input type="hidden" name="csrfmiddlewaretoken" value="5hd673HzixkXAU8fLABIft5zw0ebdNwAqjiEgS7ilYUPJHuV3zv6dWlOBxBXEwiR">-->
	</form>
2. ajax
	方式1:先编写csrf模板语法,然后利用标签查找和值获取,手动添加
	{% csrf_token %}
	<button id="d1">btn</button>
	<script>
	    $('#d1').click(function(){
	        $.ajax({
	            url: '',
	            type: 'post',
	            data: {"csrfmiddlewaretoken": $('[name="csrfmiddlewaretoken"]').val()},
	            success: function(){
	
	            }
	        })
	    })
	方式2:利用模板语法
	data: {"csrfmiddlewaretoken": "{{ csrf_token }}"}
	方式3:通用方式(js脚本)
	function getCookie(name) {
	    var cookieValue = null;
	    if (document.cookie && document.cookie !== '') {
	        var cookies = document.cookie.split(';');
	        for (var i = 0; i < cookies.length; i++) {
	            var cookie = jQuery.trim(cookies[i]);
	            // Does this cookie string begin with the name we want?
	            if (cookie.substring(0, name.length + 1) === (name + '=')) {
	                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
	                break;
	            }
	        }
	    }
	    return cookieValue;
	}
	var csrftoken = getCookie('csrftoken');
	function csrfSafeMethod(method) {
	  // these HTTP methods do not require CSRF protection
	  return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
	}
	
	$.ajaxSetup({
	  beforeSend: function (xhr, settings) {
	    if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
	      xhr.setRequestHeader("X-CSRFToken", csrftoken);
	    }
	  }
	});
	将以上代码放入js文件中,需要使用在html中导入文件即可

csrf相关装饰器

当整个网站默认都不校验csrf或者全部校验csrf,可以单独设置指定函数需不需要校验
FBV:

from django.views.decorators.csrf import csrf_protect,csrf_exempt
"""
csrf_protect:校验csrf
csrf_exempt:不校验csrf
直接在指定的视图函数上装饰即可
"""
@csrf_protect
def func1(request):
	return HttpResponse('func1')
@csrf_exempt
def func2(request):
	return HttpResponse('func2')

CBV:

"""CBV针对于装饰器不能够直接添加,需要使用专门添加装饰器的方法"""
from django import views
from django.utils.decorators import method_decorator  # 使用该模块添加装饰器
from django.views.decorators.csrf import csrf_protect, csrf_exempt

@method_decorator(csrf_protect, name='post')  # 方式2:装饰给类,指定装饰的方法名
class Index(views.View):
    @method_decorator(csrf_protect)  # 方式3:装饰所有方法
    def dispatch(self, request, *args, **kwargs):
        return super().dispatch(request, *args, **kwargs)

    def get(self, request):
        return render(request, 'login.html')

    @method_decorator(csrf_protect)  # 方式1:直接在指定方法添加装饰器
    def post(self, request):
        return HttpResponse('post')
"""针对于csrf_exempt只有方式3有效"""

auth认证模块

django执行数据库迁移命令后会产生一张auth_user表
该表可以配合auth模块做用户相关的功能:登录、注册、修改密码等
该表还是django admin后台管理默认使用的表
命令行创建django admin后台管理员:python manage.py createsuperuser

auth模块常见功能
  1. 创建用户
from django.contrib.auth.models import User  # 创建用户需要先导入该表

User.objects.create()
User.objects.create_user(username=username,password=password)
User.objects.create_superuser(username=username,password=password,email=email)  # 管理员用户需要填写邮箱
"""有三种创建方式
第一个不建议使用,密码不会自动加密
第二个为创建普通用户
第三个为创建管理员用户
"""
  1. 校验用户名与密码是否正确
from django.contrib import auth
user_obj = auth.authenticate(request,username,password)  # 如果用户名与密码能够匹配上,返回用户对象;否则返回None
  1. 用户登录
from django.contrib import auth
auth.login(request,user_obj)  # 提供一个通过校验的用户对象,会在后端为该用户生成相关的session数据
  1. 判断用户是否登录
res = request.user.is_authenticated
"""当前登录了返回True,否则返回False"""
  1. 获取登录用户对象
user_obj = request.user
"""
如果当前登录了返回当前登录用户对象
如果没有登录则返回一个匿名用户
"""
print(user_obj.username)  # 如果是匿名用户返回空
print(user_obj.password)  # 匿名用户点password会报错
  1. 校验用户登录装饰器
from django.contrib.auth.decorators import login_required
@login_required()
def func(request):
	return HttpResponse('func')
"""
如果当前用户没有登录,跳转到默认登录页面:/accounts/login/
也可以设置跳转的登录页面:login_required(login_url='/login/')
如果想要全局都使用一个登录页面,则可以在配置文件中添加配置:LOGIN_URL='/login/'
"""
  1. 校验密码是否正确
request.user.check_password('password')
"""会自动加密括号内密码判断是否与当前登录账号密码一致;返回布尔值"""
  1. 修改密码
request.user.set_password('new_password')
request.user.save()
"""
将密码修改为括号内的新密码
需要注意修改完后必须保存,否则修改不生效
"""
  1. 注销登录
from django.contrib import auth
def logout_fn(request):
	auth.logout(request)
	return HttpResponse('logout')
"""调用该函数时,会将当前请求的session信息全部清除"""

auth_user表切换

当内置的表字段不够用,想要添加更多字段,那么就可以通过继承内置的AbstractUser类,来定义一个自己的Model类
models.py:

from django.contrib.auth.models import AbstractUser
class Userinfo(AbstractUser):
	"""继承后直接扩展auth_user表中没有的字段即可"""
	phone = models.BigIntegerField()

在自定义了auth_user表后,需要在setting中配置好,当前应该使用我们自定义的表来做用户认证
setting:

AUTH_USER_MODEL = 'app01.Userinfo'  # 应用名加类名

基于django中间件设计项目功能

"""python导入模块的第三种方式:通过字符串导入"""
import importlib
s1 = 'app01.aaa.func'
res = importlib.import_module(s1)
"""
res就相当于是func.py对象,可以直接点出其中方法
需要注意此方法最多只能到py文件,不能够在细化
原理相当于是切割字符串,然后导入:s1.rsplit('.',maxsplit=1)
"""
  • 配置文件插拔式设计
    需要先创建一个配置文件
"""在里边存放想要执行的类"""
NOTIFY_FUNC_LIST = [
    'notify.qq.QQ',
    'notify.weixin.WeiXin',
    'notify.msg.Msg',
]

然后在notify包中创建各个类

class QQ(object):
    def __init__(self):
        pass  # 模拟发送qq之前 应该准备的代码环境

    def send(self, content):
        print('qq消息通知:', content)

创建启动文件

import notify  # 导入包会导入包的__init__文件

if __name__ == '__main__':
    notify.send_all('messages')

在__init__文件中执行各个模块的方法

import importlib
import settings

def send_all(content):
    for i in settings.NOTIFY_FUNC_LIST:  # 'day64.notify.qq.QQ',循环获取每个字符串
        module_path, class_str_name = i.rsplit('.', maxsplit=1)  # 'day64.notify.qq'  'QQ',将字符串分为文件路径与类名
        module = importlib.import_module(module_path)  # 获取py文件对象
        class_name = getattr(module, class_str_name)  # 通过文件对象与文件对象中的方法(类名)字符串,使用反射获取真正的类名
        obj = class_name()  # 实例化一个对象
        obj.send(content)  # 由于是鸭子类型,所有类都是同一个方法
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值