Day 64 django csrf操作 auth认证模块 项目功能封装优化

1、csrf跨站请求伪造

简介
钓鱼网站:假设是一个银行一摸一样的网址页面 用户 用户在该页面上转账
账户的钱会减少 但是受益人却不是自己想要转账的那个人

模拟
一台计算机上两个服务端不同端口启动 钓鱼网站地址改为正规网站的地址

钓鱼网站
style="display: none"

div class="container">
        <div class="row">
            <form action="https://127.0.0.1/8000/transfer/" method="post">
                <p>用户名:<input type="text" name="user"></p>
                <p>转入用户:<input type="text"></p>
                <p><input type="text" name="target" value="kk" style="display: none"></p>
                <p>转账金额<input type="text" name="price"></p>
                <p><input type="submit" name="转账"></p>
            </form>

        </div>
    </div>

预防
csrf策略:通过在返回的页面上添加独一无二的标识信息从而区分正规网站和钓鱼网站的请求

2、csrf操作

2.1、form表单

<form action="" method=:"post">
    {% csrf_token %}
</form>

2.2、ajax

方式一: 先编写csrf模板语法 然后利用标签查找和值获取 手动添加

{% csrf_token %}
#  利用属性选择器查找
data:  {'username':'jason','csrfmiddlewaretoken':$('[name="csrfmiddlewaretoken"]')}

方式二: 直接利用模板语法即可

data:{'username':'jason','csrfmiddlewaretoken':'{{ csrf_token }}'}

方式三: 通用方式(js脚本)
扩展性更高高

# 在配置文件中中 配置固定地址
STATICFILES_DIRS = [
    os.path.join(BASE_DIR,'static')
]

#直接在html中引入
<script src="/static/csrf.js"></script>

创建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);
    }
  }
});

3、csrf相关装饰器

当整个网站默认都不校验csrf 但是局部视图函数需要校验

当整个网站默认都校验csrf 但是局部视图函数不许哟啊校验

3.1、FBV

需要先导入 模块 导入装饰器

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

校验csrf
csrf_protect

不校验csrf
csrf_exempt

@csrf_protect
def home(request):
    return HttpResponse('hahaha')

3.2、CBV

针对CBV不能直接在方法上添加装饰器 需要借助于专门添加装饰器的方法

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

#方式二:直接在类上面添加 通过指名道姓装饰给类下的方法
@method_decorator(csrf_protect, name='post')
class MyHome(views.View):
    #方式三:等于 类中所有方法添加 装饰器(且 csrf_exempt装饰器 只用该方式有效)
    @method_decorator(csrf_protect)
    def dispatch(self, request, *args, **kwargs):
        return super(MyHome, self).dispatch(request,*args,**kwargs)

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

    @method_decorator(csrf_protect)  #方式一:指名道姓 直接给类下的方法上添加
    def post(self, request):
        return HttpResponse('嘿嘿嘿')

注意:针对csrf_exe,pt只有方式三有效 针对其他装饰器上述三种方式都有效

4、auth认证模块

django执行数据库迁移命令之后会产生一个auth_user表
该表可以配合auth模块坐用户相关的功能:注册、扽牢固、修改密码、注销····
该表还是django admin后台管理默认的表

django admin后台管理员账号创建
python manage.py createsuperuser

4.1、auth模块常见功能

校验用户名是否正确

from django.contrib import auth

is_user_obj = auth.authenticate(request,username=username,password=password)

登录用户

auth.login(request,user_obj)

判断用户是否登录

print(request.user.is_authecticated) #返回布尔值

校验用户登录装饰器
@login_required(login_url='/login/')

from django.contrib.auth.decorators import login_required

#登录函数
def login(request):
    from django.contrib import auth
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        is_user_obj = auth.authenticate(request, username=username, password=password)
        if is_user_obj:
            auth.login(request, is_user_obj)  # 自动操作cookie和session
        # print(is_user_obj.password)
        # print(is_user_obj.pk)

# 跳转局部配置 跳转至登录 网页
@login_required(login_url='/login/')
def index(request):
    return HttpResponse('index')

#跳转全局配置 在配置文件中 直接配置
LOGIN_URL = '/login/'

修改密码
校验旧密码是否正确

request.user.check_password(old_password)

修改密码

request.user.set_password(new_password)
request.user.save()

注销用户

auth.logout(request)

创建用户
create_user()创建普通用户
create_superuser()创建管理员用户 必须要添加邮箱字段

# 导入 该表的类
from django.contrib.auth.models import User
def reg(request):
    User.objects.create_user(username='kk',password=123)
    User.objects.create_superuser(username='ming',password='hong',email='888@163.com')
    return HttpResponse('注册功能')

4.2、auth_user 表切换

我们还想使用auth模块的方法并且扩展auth_user表字段

在models 给表坐扩展

from django.contrib.auth.models import AbstractUser


class Userinfo(AbstractUser):
    """扩展 auth_user表中没有的字段"""
    # 创的时候 可以添加 参数使字段可以为空或 null=True
    phone = models.BigIntegerField()
    address = models.TextField()

还需要 在 配置文件中 修改配置

AUTH_USER_MODEL = 'app01.Userinfo'

5、基于django中间件涉及项目功能

首先 需要创建 一个包 将所有功能都分为py文件 存放在包下 还需创建配置文件 启动文件

在功能py文件中将功能封装为类 将功能使用 用相同的方法名 封装

class QQ(object):
    def __init__(self):
        pass

    def send(self, content):
        print(f'qq发送消息:{content}')

创建settings 配置文件
将包下的功能类 的调用路径全部以字符串形式 封装为一个列表

PACK_LIST = [
    'packet.qq.QQ',
    'packet.vx.VX',
    'packet.tt.TT',
]

在启动文件中 调用包 就是调用包下的双下init 文件
所以主要 的逻辑 都双下init.py文件下 通过 调用importlib模块 和settings文件
import importlib

import importlib
import settings

def send_all(content):
    #循环 取出 配置文件中封装好的路径
    for i in settings.PACK_LIST:
        #以 点从右往左切割 一次  取出类名 和 调用模块路径
        models_path,class_str_name=i.rsplit('.',maxsplit=1)
		#调用模块
        models=importlib.import_module(models_path)
		# 利用反射 getattr方法 视文件作为对象 将该字符串相同的 属性取出 即取出类名
        class_name=getattr(models,class_str_name)
        # 类名加括号 实例化对象
        obj=class_name()
		#点功能相同的 方法 并传入相同的参数 即可以 一起调动
        obj.send(content)
09-14 04:21