Django之csrf和cbv

2022/9/14 6:19:03

本文主要是介绍Django之csrf和cbv,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

csrf跨站请求伪造

介绍
1.简介
	钓鱼网站:假设是一个跟银行一模一样的网址页面 用户在该页面上转账
	账户的钱会减少 但是受益人却不是自己想要转账的那个人
2.模拟
	一台计算机上两个服务端不同端口启动 钓鱼网站提交地址改为正规网站的地址
3.预防
	csrf策略:通过在返回的页面上添加独一无二的标识信息从而区分正规网站和钓鱼网站的请求
模拟钓鱼网站和真实网站
# 真实网站
def transfer(request):
    if request.method == 'POST':
        username = request.POST.get('name')
        target_name = request.POST.get('target_name')
        money = request.POST.get('money')
        print(f'{username}给{target_name}转了{money}钱')
    return render(request,'transfer.html')
	
前端代码:
<h1>真网站</h1>
<form action="" method="post">
    <p>name: <input type="text" name="name"></p>
    <p>target_name : <input type="text" name="target_name"></p>
    <p>money : <input type="text" name="money"></p>
    <input type="submit">
</form>
# 钓鱼网站:
 def transfer(request):
    return render(request,'transfer.html')
	
前端代码:
  <h1>钓鱼网站</h1>
 <form action="http://127.0.0.1:8000/transfer/" method="post">
    <p>name: <input type="text" name="name"></p>
    <p>target_name : <input type="text" >
                     <input type="text" name="target" value="jerry" style="display: none">

    </p>
    <p>money : <input type="text" name="money"></p>
    <input type="submit">
 </form>

image

csrf操作(解决措施)
'''先打开settings里面的MIDDLEWARE的第四行'django.middleware.csrf.CsrfViewMiddleware''''
全局校验 需要携带一串随机字符串验证通过才可以朝服务端发送post请求

![image](https://img20image

form表单方法:
1.给form表单内部添加方法
<form action="" method="post">
    {% csrf_token %}  # 前后端分离的时候用不了这个方法
</form> 
# 这时候就会产生一串随机字符串 当提交post请求的时候 服务端会自动校验身份 

Ajax方法:
# 方法1:先编写csrf模板语法 然后利用标签查找和值获取 手动添加
{% csrf_token %}
<button id=" d1">ajax</button>
<script>
    $('#d1').click(function () {
        $.ajax({
            url: '',
            type: 'post',
            data: {'username': 'summer', 'csrfmiddlewaretoken': $('[name = "csrfmiddlewaretoken"]').val()},
            success:function (args){

            }
        })
    })
</script>

# 方法2:直接利用模板语法
  data:{'username': 'summer', '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文件夹内即可

image

csrf相关装饰器
1.当整个网站默认都不校验csrf 但是局部视图函数需要校验 如何处理 
    # 注掉settings里面的MIDDLEWARE的第四行代码
2.当整个网站默认都校验csrf 但是局部视图函数不需要校验 如何处理
# FBV 

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

@csrf_protect  # csrf校验
def home(request):
    return HttpResponse('下午好啊,北鼻!')
	
'''
csrf_exempt  不校验csrf
csrf_protect  校验csrf
'''
CBV添加装饰器的多种方式
# CBV
from django import views
from django.utils.decorators import method_decorator


# @method_decorator(csrf_protect , name='post')  # 方式2 可以指定给哪个方法装
class MyHome(views.View):
    @method_decorator(csrf_protect)  #方式3 影响类中的所有方法
    def dispatch(self, request, *args, **kwargs):
        super(MyHome, self).dispatch(request, *args, **kwargs)

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

    # @method_decorator(csrf_protect)  # 方式1
    def post(self, request):
        return HttpResponse('home post view')

'''
针对CBV不能直接在方法上添加装饰器 需要借助于专门添加装饰器的方法
from django.utils.decorators import method_decorator
'''
#  @method_decorator(csrf_exempt)  针对不校验csrf只有继承的dispatch方法可以使用

auth认证模块

django执行数据库迁移命令以后会产生一个auth_user表
基于这张表可以创建一个管理员用户
python manage.py createsupersuer 
该表可以配合auth模块操作用户相关的功能:注册 登录 删除 修改等
auth模块常见功能
1.创建用户
  from django.contrib.auth.models import User
  user.object.create_user(username,password)
  user.object.create_superuser(username,password,email)
    
2. 校验用户名和密码是否正确
  from django.contrib import auth
  auth.authenticate(request,username,password)

3.用户登录
  auth.login(request,user_obj)
    
4.判断用户是否登录
  request.user.is_authenticated
    
5.获取登录用户对象
  request.user
    
6.校验用户登录装饰器
 from django.contrib.auth.decorators import login_required
 跳转局部配置
 login_required(login_url='/login/')
 跳转全局配置 在settings里面配置需要跳转的页面 适合操作量大的数据
 LOGIN_URL = '/login/'
    
    
7.检验密码是否正确
  request.user.check_password(old_password)
    
8.修改密码
  request.user.set_password(new_password)
  request.user.save() 

9.注销登录
  auth.logout(request)
代码实现
from django.contrib import auth
from django.contrib.auth.decorators import login_required


def login(request):
    print(request.user)
    '''
    request.user 该方法登录成功(auth.login)会返回一个当前登录对象  
                 没有登录(auth.login)会返回一个AnonymousUser  匿名用户对象
    '''
    print(request.user.is_authenticated)  # 判断当前用户是否登录 返回的是布尔值

    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        # 查询数据库 校验数据 密码自动加密比对
        user_obj = auth.authenticate(request, username=username, password=password)
        print(user_obj)  # 该方法返回的是对象 如果没有则返回None
        if user_obj:
            # 记录用户登录状态
            auth.login(request, user_obj)  # 自动创建session表 返回随机字符串给前端
    return render(request, 'login.html')


@login_required(login_url='/login/')  # 局部配置  每次都需要自己写
def index(request):
    return HttpResponse('登录index')


@login_required(login_url='/login/')
def func(request):
    return HttpResponse('登录func')


@login_required
def set_password(request):
    if request.method == 'POST':
        old_password = request.POST.get('old_password')
        new_password = request.POST.get('new_password')
        # 1.校验原密码是否正确
        res = request.user.check_password(old_password)
        if res:
            # 修改密码
            request.user.set_password(new_password)
            # 保存密码
            request.user.save()
    return render(request,'set_password.html')


@login_required
def logout(request):
    auth.logout(request)  # 自动清除cookie和session
    return HttpResponse('注销功能')



from django.contrib.auth.models import User
def register(request):
    User.objects.create_user(username='summer',password=123)  # 创建普通用户
    User.objects.create_superuser(username= 'jerry',password=123,email='123@qq.com')  # 创建管理员用户
    return HttpResponse('注册功能')
auth_user表切换
# 想创建更多的表的字段 相当于自定义auth_user表
第一步:
from django.contrib.auth.models import AbstractUser

class Userinfo(AbstractUser):
    phone = models.BigIntegerField()
    desc = models.TextField()

第二步:
在settings中配置
AUTH_USER_MODEL = 'app01.Userinfo'

auth模块的功能都可以用 除了自己创建的字段 其他的都一样操作

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

import importlib  # 功能是通过字符串来导模块

s1 = 'b.ddd'
res = importlib.import_module(s1)  # from b import ddd
print(res.s)
# 导入模块的底层原理 : 首先拿到字符串 按最右边的切割  s1.rsplit('.',maxsplit=1)  右边的单位最小为py文件   切完结果 ['b', 'ddd']
函数封装
def send_qq(content):
    print('qq消息通知:',content)

def send_we(content):
    print('微信消息通知:',content)

def send_msg(content):
    print('短信消息通知:',content)

def send_all(content):
    send_qq(content)
    send_we(content)
    send_qq(content)
	
if __name__ == '__main__':
    send_all('放假通知!!!')
配置文件插拔式设计
# 创建settings.py文件 模仿中间件
NOTIFY_FUNC_LIST = [
    'notifys.notify.qq.QQ',
    'notifys.notify.weixin.Weixin',
    'notifys.notify.msg.Msg',
]
# 创建需要发送消息的py文件
class QQ(object):
    def __init__(self):
        pass
    def send(self,content):
        print('qq消息通知:',content)
自定义一个文件 创建一个__init__.py
# __init__.py 代码
import importlib
import settings


def send_all(content):
    for i in settings.NOTIFY_FUNC_LIST:
        module_path, class_str_name = i.rsplit('.', maxsplit=1)
        module = importlib.import_module(module_path)
        class_name = getattr(module, class_str_name)  # 真正的类名
        obj = class_name()
        obj.send(content)



这篇关于Django之csrf和cbv的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程