Django CSRF与auth模块

Django CSRF与auth模块

CSRF

FORM表单中怎么通过CSRF校验

只需要在form表单中写一个

{% csrf_token %}

ajax通过asrf校验有三种方法

$.ajax({
            url:'',
            type:'post',
            {#data:{'username':'yang'},#}
            //第一种方式 自己手动获取
            {#data:{'username':'yang','csrfmiddlewaretoken':$('input[name="csrfmiddlewaretoken"]').val()},#}
            //第二种方式 利用模板语法
            {#data:{'username': 'yang', 'csrfmiddlewaretoken':'{{ csrf_token }}'},#}
            //第三种方式 通用方式 需要引入外部js文件
            data:{'username':'yang'},
            success:function (data) {
                alert(data)
            }
        })

第三种需要引入外部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');
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来实现的)


CSRF相关装饰器

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

应用场景:

  • 当网站整体都校验csrf的时候,想让某几个视图函数不校验
  • 当网站整体都不校验csrf的时候,想让某几个视图函数校验

csrf_exempt:不校验

csrf_protect:校验

# @csrf_exempt    # 不校验csrf
@csrf_protect  	# 校验csrf
def index(request):
    print('我是视图函数index')

    def render():
        return HttpResponse('我是index里面的render函数')

    obj = HttpResponse('index')
    obj.render = render
    return obj

给FBV装饰,导入后直接加装饰器就行

但是给CBV加装饰器,有三种方式

需要导入一个方法,使用这个方法method_decorator(csrf_protect)

  1. 加在CBV视图的某个方法上
from django.views import View
from django.utils.decorators import method_decorator

class MyHome(View):

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

    @method_decorator(csrf_protect) 	# 第一种方式
    def post(self, request):
        return HttpResponse('post')
  1. 直接加在视图类上,但是method_decorator需要传入name关键字参数
from django.views import View
from django.utils.decorators import method_decorator

@method_decorator(csrf_protect, name='post')  # 第二种,知名道姓的给类的某个方法装饰
class MyHome(View):

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

    def post(self, request):
        return HttpResponse('post')
  1. 加在dispatch方法上

在匹配类方法之前,都需要dispatch方法分发,所以给该方法装饰,就代表整个类中的方法都是校验或不校验

from django.views import View
from django.utils.decorators import method_decorator

class MyHome(View):

    @method_decorator(csrf_protect)		# 第三种 类中所有的方法都装
    def dispatch(self, request, *args, **kwargs):
        return super().dispatch(request,*args,**kwargs)

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

    def post(self, request):
        return HttpResponse('post')

CBV中首先执行的就是dispatch方法,所以这么写相当于给get和post方法都加上了登录校验。

补充

CSRF Token相关装饰器在CBV只能加到dispatch方法上,或者加在视图类上然后name参数指定为dispatch方法。

  • csrf_protect,为当前函数强制设置防跨站请求伪造功能,即便settings中没有设置全局中间件。
  • csrf_exempt,取消当前函数防跨站请求伪造功能,即便settings中设置了全局中间件。
from django.views import View
from django.utils.decorators import method_decorator

class MyHome(View):
    @method_decorator(csrf_exempt)
    def dispatch(self, request, *args, **kwargs):
        return super().dispatch(request,*args,**kwargs)

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

    def post(self, request):
        return HttpResponse('post')

or

from django.views import View
from django.utils.decorators import method_decorator

@method_decorator(csrf_exempt, name='dispatch')
class MyHome(View):
    def dispatch(self, request, *args, **kwargs):
        return super().dispatch(request,*args,**kwargs)

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

    def post(self, request):
        return HttpResponse('post')

注意:给CBV加装饰器,推荐使用模块method_decorator,csrf_exempt只能给dispatch方法装


auth模块

Django用户相关的自带的功能模块

导入模块

from django.contrib import auth
from django.contrib.auth.models import User

auth模块常用方法:

1.创建用户
  • create()

虽然可以创建,但是密码是明文,对后面的密码校验修改密码等功能都有影响,所以不推荐使用

User.objects.create(username='用户名',password='密码',email='邮箱',...)
  • create_user()

auth提供的一个创建新用户的方法,需要提供必要参数(username, password)

User.objects.create_user(username='用户名',password='密码',email='邮箱',...)
  • create_superuser()
User.objects.create_superuser(username='用户名',password='密码',email='邮箱',...)
2.校验用户名和密码是否正确
  • authenticate()

提供了用户认证功能,需要username 、password两个关键字参数

authenticate(username='usernamer',password='password')

注意:

  • 认证成功(用户名和密码正确有效),便会返回一个 User 对象
  • 认证失败(用户名和密码不正确),便会返回一个 None
3.保存用户登录状态(session)
  • login()

可以实现一个用户登录的功能,需要一个HttpRequest对象,以及一个经过认证的User对象

def login(request):
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        user_obj = auth.authenticate(request, username=username, password=password)
        """
        用户名密码正确返回的是用户对象
        错误的话返回的是None
        """
        if user_obj:
            auth.login(request, user_obj)
            return HttpResponse('登录成功')
    return render(request, 'login.html')

只要执行了这个方法,之后在任意可以获取到request对象的地方,都可以通过request.user获取当前登录的对象

4.判断是否登录以及获取当前登录用户对象
  • is_authenticated()

用来判断当前请求是否通过了认证

request.user.is_authenticated()	# 返回布尔值
  • request.user

获取登录用户对象

5.登录装饰器
  • login_required()

auth 给我们提供的一个装饰器工具

from django.contrib.auth.decorators import login_required

@login_required()
def is_login(request):
    pass

若用户没有登录,则会跳转到django默认的 登录URL '/accounts/login/ ' 并传递当前访问url的绝对路径 (登陆成功后,会重定向到该路径).

可以自定义登录的URL,在settings.py文件中通过LOGIN_URL进行修改

# 全局配置:
LOGIN_URL = '/login/'  # 这里配置成你项目登录页面的路由
# 局部配置:
@login_required(login_url='/login/')

若两者都配置了,优先执行局部的配置

6.判断密码是否正确
  • check_password()

auth提供的一个检查密码是否正确的方法,需要传入当前请求用户的密码,返回布尔值

is_right = request.user.check_password(old_password)
7.修改密码
  • set_password()

auth 提供的一个修改密码的方法,接收要设置的新密码

注意:一定要调用user.save方法保存

user.set_password(password='')
user.save()

修改密码的例子

@login_required()
def set_password(request):
    if request.method == 'POST':
        old_password = request.POST.get('old_password')
        new_password = request.POST.get('new_password')
        is_right = request.user.check_password(old_password)# 判断旧密码是否正确
        print(is_right)
        if is_right:
            request.user.set_password(new_password)	# 设置新密码
            request.user.save() # save保存
    return render(request, 'set_password.html')
8.注销功能
  • logout()

需要一个request参数,没有返回值

当调用该函数时,当前请求的session信息会全部清除。该用户即使没有登录,使用该函数也不会报错

@login_required()
def logout(request):
    auth.logout(request)
    return HttpResponse('注销成功')

扩展默认的auth_user表

我们可以通过继承内置的AbstractUser 类,来定义一个自己的Model类,这样既能根据项目需求灵活的设计用户表,又能使用Django强大的认证系统

利用类的继承

from django.contrib.auth.models import User,AbstractUser

class UserInfo(AbstractUser):
    phone = models.CharField(max_length=11, null=True)
    avatar = models.FileField()
    
    def __str__(self):
        return self.username

注意:

按上面的方式扩展了内置的auth_user表之后,要在settings.py中告诉Django,我现在使用我新定义的UserInfo表来做用户认证。

写法如下:AUTH_USER_MODEL = '应用名.表名'

# 引用Django自带的User表,继承使用时需要设置
AUTH_USER_MODEL = "app名.UserInfo"

再次注意:

一旦我们指定了新的认证系统所使用的表,我们就需要重新在数据库中创建该表,而不能继续使用原来默认的auth_user表了

原文地址:https://www.cnblogs.com/YGZICO/p/12198766.html