django csrf跨站,CBV添加装饰器,auth认证模块

django csrf跨站,CBV添加装饰器,auth认证模块

内容概要

csrf跨站请求伪造

csrf相关校验策略

CBV添加装饰器的多种方式

auth认证模块

BBS项目需求分析

内容详情

csrf跨站请求伪造

钓鱼网站:模仿一个正规的网站 让用户在该网站上操作 但是操作的结果会影响到用户正常的网站账户 但是其中会有一些暗箱操作

例如:英语四六级考试需要网上先缴费 但是你会发现卡里的钱扣了但是却交到了一个莫名其妙的账户 并不是真正的四六级官方账户

模拟钓鱼网站案例:转账案例

​ 内部隐藏标签

如何区分真假网站页面发送的请求

正常请求

<form action="" method="post">
    <h1>我是真正的网站</h1>
    <p>用户名:<input type="text" name="username"></p>
    <p>转账账户:<input type="text" name="transfer"></p>
    <p>转账金额:<input type="text" name="money"></p>
    <input type="submit" value="转账">

</form>

image

钓鱼网站的暗箱操作

<form action="http://127.0.0.1:8000/index/" method="post">
    <h1>我是钓鱼网站</h1>
    <p>用户名:<input type="text" name="username"></p>
    <p><input type="hidden" name="transfer" value="我是钓鱼者账户"></p>
    <p>转账账户<input type="text"></p>
    <p>转账金额<input type="text" name="money"></p>
    <input type="submit" value="转账">

</form>

image

csrf校验策略

在提交数据的位置添加唯一标识

1.form表单csrf策略

form表单内部添加{% csrf_token %}

打开配置文件csrf校验中间件

 'django.middleware.csrf.CsrfViewMiddleware',

在前端页面添加校验

<form action="" method="post">
    <h1>我是真正的网站</h1>
    {% csrf_token %}
    <p>用户名:<input type="text" name="username"></p>
    <p>转账账户:<input type="text" name="transfer"></p>
    <p>转账金额:<input type="text" name="money"></p>
    <input type="submit" value="转账">

</form>

有唯一标识可以通过校验正常使用功能

image

没有唯一标识无法通过校验

image

如果不是真正网站的csrf_token,自己伪造的不行

image

2.ajax请求csrf策略

方式1:自己动手取值 较为繁琐

data:{'csrfmiddlewaretoken':$('input[name="csrfmiddlewaretoken"]').val()},
    
    
$.ajax({
  url: "/cookie_ajax/",
  type: "POST",
  data: {
    "username": "Tonny",
    "password": 123456,
    "csrfmiddlewaretoken": $("[name = 'csrfmiddlewaretoken']").val()  // 使用JQuery取出csrfmiddlewaretoken的值,拼接到data中
  },
  success: function (data) {
    console.log(data);
  }
})

方式2:利用模板语法自动获取(一定要用引号引起来)

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

方式3:直接引入一个js脚本即可

或者用自己写一个getCookie方法:

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');

每一次都这么写太麻烦了,可以使用$.ajaxSetup()方法为ajax请求统一设置。

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

将下面的文件配置到你的Django项目的静态文件中,在html页面上通过导入该文件即可自动帮我们解决ajax提交post数据时校验csrf_token的问题,(导入该配置文件之前,需要先导入jQuery,因为这个配置文件内的内容是基于jQuery来实现的)

放在一个js文件中然后再页面中引入js文件即可

$('#ajax').click(function () {
        $.ajax({
            url: '',
            type: 'post',
            data: {'username': '张三', 'transfer': '官方账户', 'money': 10000},
            success:function () {
                alert('转账成功')
            }
        })
    })

image

csrf相关装饰器

整个django项目都校验csrf 但是某些视图函数/视图类不想校验

整个django项目都不校验csrf 但是某些个视图函数/视图类想要校验

FBV添加装饰器的方式

与正常函数添加装饰器一致

取消校验csrf

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


@csrf_exempt
def index_func1(request):
    if request.method == 'POST':
        username = request.POST.get('username')
        transfer = request.POST.get('transfer')
        money = request.POST.get('money')
        print(f'{username}转账给{transfer}金额{money}元')
        return render(request, 'indexPage1.html')

单个校验csrf

from django.views.decorators.csrf import csrf_exempt,csrf_protect
@csrf_protect
def index_func2(request):
    if request.method == 'POST':
        username = request.POST.get('username')
        transfer = request.POST.get('transfer')
        money = request.POST.get('money')
        print(f'{username}转账给{transfer}金额{money}元')

    return render(request, 'indexPage2.html')

CBV添加装饰器的方式

与正常情况不一样 需要注意 主要有三种方式

方式1:单独生效

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


class MyView(View):
    def get(self, request):
        return render(request, 'indexPage1.html')

    @csrf_protect # 不能直接装饰
    def post(self, request):
        username = request.POST.get('username')
        transfer = request.POST.get('transfer')
        money = request.POST.get('money')
        print(f'{username}转账给{transfer}金额{money}元')
        return render(request, 'indexPage1.html')

image

报错,CBV不能直接添加装饰器

需要使用一个方法进行装饰

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

class MyView(View):
    def get(self, request):
        return render(request, 'indexPage1.html')

    # @csrf_protect # 不能直接装饰

    @method_decorator(csrf_protect)
    def post(self, request):
        username = request.POST.get('username')
        transfer = request.POST.get('transfer')
        money = request.POST.get('money')
        print(f'{username}转账给{transfer}金额{money}元')
        return render(request, 'indexPage1.html')

image

使用方法装饰后就可以正常使用了

方式2:单独生效

@method_decorator(csrf_protect, name='post')
class MyView(View):
    def get(self, request):
        return render(request, 'indexPage1.html')

    # @csrf_protect # 不能直接装饰
    def post(self, request):
        username = request.POST.get('username')
        transfer = request.POST.get('transfer')
        money = request.POST.get('money')
        print(f'{username}转账给{transfer}金额{money}元')
        return render(request, 'indexPage1.html')

方式3:整个类中生效

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


class MyView(View):
    @method_decorator(csrf_protect)  # cbv拦截装饰方法
    def dispatch(self, request, *args, **kwargs):
        return super().dispatch(request, *args, **kwargs)

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

    # @csrf_protect # 不能直接装饰
    def post(self, request):
        username = request.POST.get('username')
        transfer = request.POST.get('transfer')
        money = request.POST.get('money')
        print(f'{username}转账给{transfer}金额{money}元')
        return render(request, 'indexPage1.html')

注意事项

有一个装饰器是特里只能有一种添加方式csrf_exempt

只有在dispatch方法添加才会生效

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

class MyView(View):
	@method_decorator(csrf_exempt)  # 取消校验
    def dispatch(self, request, *args, **kwargs):
        return super().dispatch(request, *args, **kwargs)

auth认证模块

django自带一个admin路由 但是需要我们提供管理员账号和密码

如果想要使用admin后台管理 需要先创建表 然后创建管理员账号直接执行数据库迁移命令即可产生默认的auth_user表 该表就是admin管理后台默认的认证表

1.创建超级管理员

python manage.py createsuperuser

![image-20221227191253242](django csrf跨站,CBV添加装饰器,auth认证模块.assets/image
)

image

基于auth_user表编写用户相关的各相功能

登录、校验用户是否登录、修改密码、注销登录等

auth认证相关模块及操作

用户注册

def login_func(request):
    if request.method == 'POST':
        username = request.POST.get('username')
        pwd = request.POST.get('pwd')
        # User.objects.create(username=username,password=pwd)  # 不加密
        User.objects.create_user(username=username, password=pwd)  # 密码加密正常创建用户用这个

image

判断用户是否登录成功

自动校验用户名密码,并且自动创建session

user_obj = auth.authenticate(request,
                                     username=username,
                                     password=pwd)  # 判断是否登录成功
        if user_obj:
            print('登录成功')
            # 用户登录成功(返回给客户端登录的凭证,令牌,随机字符串)
            auth.login(request, user_obj)  # 自动操作djangosession表
            return render(request, 'login.html')

image

判断用户是否登录

结合登录注册

print(request.user)  # 查看用户名
print(request.user.is_authenticated)  # 查看用户是否已登录
def login_func(request):
    print(request.user)
    print(request.user.is_authenticated)  # 判断当前用户是否以登陆
    if request.method == 'POST':
        username = request.POST.get('username')
        pwd = request.POST.get('pwd')

        user_obj = auth.authenticate(request,
                                     username=username,
                                     password=pwd)  # 判断是否登录成功
        if user_obj:
            print('登录成功')
            # 用户登录成功(返回给客户端登录的凭证,令牌,随机字符串)
            auth.login(request, user_obj)  # 自动操作djangosession表
            return render(request, 'login.html')
        print('登录失败')

    return render(request, 'login.html')


def home(request):
    return render(request, 'homePage.html', locals())
{% if request.user.is_authenticated %}
    <a href="">登录用户</a><a href="">{{ request.user }}</a>
{% else %}
    <a href="/login/">登录</a><a href="/login/">注册</a>
{% endif %}

校验装饰器

配置文件中LOGIN_URL = '/login/'


from django.contrib.auth.decorators import login_required
@login_required(login_url='/login/')  # 可以指定用户没有登录跳转的地址,每个都可自己手动指定跳转地址
def logined_func(request):
    print('登录后才能看的页面')
    return HttpResponse('登录后才能看的页面')

结合登录功能

def login_func(request):
    print(request.user)
    print(request.user.is_authenticated)  # 判断当前用户是否以登陆
    if request.method == 'POST':
        username = request.POST.get('username')
        pwd = request.POST.get('pwd')

        # # User.objects.create(username=username,password=pwd)  # 不加密
        # User.objects.create_user(username=username, password=pwd)  # 密码加密正常创建用户用这个

        user_obj = auth.authenticate(request,
                                     username=username,
                                     password=pwd)  # 判断是否登录成功
        if user_obj:
            print('登录成功')
            # 用户登录成功(返回给客户端登录的凭证,令牌,随机字符串)
            auth.login(request, user_obj)  # 自动操作djangosession表
            return redirect(request.GET.get('next'))
        print('登录失败')

    return render(request, 'login.html')



使用全局配置

# 使用全局配置全局 # LOGIN_URL = '/login/'
@login_required
def logined_func(request):
    print('登录后才能看的页面')
    return HttpResponse('登录后才能看的页面')

校验原密码是否正确

res = request.user.check_password(原密码)

修改密码

request.user.set_password(新密码)
request.user.save()
在忘记原密码时使用下面方法可以进行密码修改
res_obj = User.objects.filter(username='qwe').first()  # 首先拿到要修改的对象
res_obj.set_password('1234')  # 修改密码
res_obj.save()  # 保存密码就行了

退出登录

auth.logout(request)

扩展auth_user表

既想使用auth模块的功能 并且又想扩展auth_user表的字段

思路1:一对一字段关联

思路2:替换auth_user表

步骤1:模型层编写模型类继承AbstractUser

from django.contrib.auth.models import AbstractUser

class UserInfo(AbstractUser):
    phone = models.CharField(max_length=32,verbose_name='手机号')
    desc = models.TextField(verbose_name='详情')

步骤2:一定要在配置文件中声明替换关系

AUTH_USER_MODEL = 'app01.UserInfo'

不使用新库扩展自定义auth_user表

替换还有一个前提 就是数据库迁移没有执行过(auth相关表没有创建)

如果非要创建那么可以在写好自定义auth_user表后,删除数据库里面django创建的表,保留自己在models里面创建的表,然后重新makemigrations后,删除,migrations文件夹里面记录的,自己创建的表后,在执行migrate就创建好自己自定义添加的auth_user表了

image

image

image

image

models.UserInfo.objects.create_user(username=username, password=pwd, phone='123331', desc='坤坤')

![image-20221227211819993](django csrf跨站,CBV添加装饰器,auth认证模块.assets/image
)

判断登录还是使用request.user进行判断

print(request.user)
print(request.user.is_authenticated)  # 判断当前用户是否以登陆

只有在进行模型类操作使用自己写的类,其余与django自动创建,使用方式一样

user_obj = auth.authenticate(request,
                                     username=username,
                                     password=pwd)  # 判断是否登录成功
        if user_obj:
            print('登录成功')
            # 用户登录成功(返回给客户端登录的凭证,令牌,随机字符串)
            auth.login(request, user_obj)  # 自动操作djangosession表
            return redirect(request.GET.get('next'))
        print('登录失败')
posted @ 2022-12-27 21:26  clever-cat  阅读(22)  评论(0编辑  收藏  举报