csrf跨站请求的相关装饰器、Auth模块(模块的使用、相关方法、退出系统、修改密码功能、注册功能)、扩展默认的auth_user表

一、csrf跨站请求的相关装饰器

'''
django.middleware.csrf.CsrfViewMiddleware

Django中有一个中间件对csrf跨站做了验证,我只要把csrf的这个中间件打开,
那就意味着所有的方法都要被验证
'''

在所有的视图函数中:
	只有几个视图函数做验证
	只有几个函数不做验证

csrf_protect: 哪个视图函数加了这个装饰器,这个函数就会做验证
csrf_exempt:哪个视图函数加了这个装饰器,这个函数就不会做验证
-------------------------------------------------------------------------------
注意:加入装饰器验证csrf,先导入下面这行代码:
from django.views.decorators.csrf import csrf_exempt,csrf_protect

一、FBV模式下:
情境11.先在settings.py配置文件中注释下面这行代码:
	# 'django.middleware.csrf.CsrfViewMiddleware',
	2.然后在需要验证的视图函数上面加上 @csrf_protect 则说明这个视图函数需要经过验证.
		@csrf_protect
		def index(request):
		    return render(request, 'index.html')
		
		def func(request):
		    return render(request, 'func.html')
	3. 上述两个视图函数中,由于index函数加了装饰器csrf_protect
		所以需要经过csrf验证,而func函数不需要

情境21.先打开settings.py配置文件中下面这行代码:即不用注释
	'django.middleware.csrf.CsrfViewMiddleware',
	2.然后在不需要验证的视图函数上面加上 @csrf_exempt 则说明这个视图函数不需要经过验证,
		而没有加任何装饰的视图函数必须经过csrf验证
		@csrf_exempt
		def index(request):
		    return render(request, 'index.html')
		
		def func(request):
		    return render(request, 'func.html')
				    return render(request, 'func.html')
	3. 上述两个视图函数中,在'django.middleware.csrf.CsrfViewMiddleware',
		没有被注释的情况下:由于index函数加了装饰器csrf_exempt,
		所以不需要经过csrf验证,而func函数需要csrf验证。

情境31.在打开settings.py配置文件中下面这行代码的情况下:
	'django.middleware.csrf.CsrfViewMiddleware',
	2.然后在不需要验证的视图函数上面加上 @csrf_exempt 则说明这个视图函数不需要经过验证,
		而另一个加了装饰器 csrf_protect 的视图函数也必须经过csrf验证
		@csrf_exempt
		def index(request):
		    return render(request, 'index.html')
		
		@csrf_protect
		def func(request):
		    return render(request, 'func.html')
	3. 上述两个视图函数中,由于index函数加了装饰器csrf_exempt
		所以不需要经过csrf验证,而func函数加了装饰器csrf_protect需要csrf验证。

二、CBV模式下:
注意:加入装饰器,先导入下面代码:
from django.views.decorators.csrf import csrf_exempt,csrf_protect
from django.views import View
from django.utils.decorators import method_decorator

方式1:在post函数上,加入csrf_exempt无效,还是报错:Forbidden (403)
	1.先打开settings.py配置文件中下面这行代码:即不用注释
	'django.middleware.csrf.CsrfViewMiddleware',
	2.然后在不需要验证的视图函数上面加上 @csrf_exempt 则说明这个视图函数不需要经过验证,
		但是结果是还需要验证,说明此方式无效。
		class Login(View):
	    # 不让post方法做验证
	    @method_decorator(csrf_exempt)
	    def post(self, request):
	        print('post')
	        return HttpResponse('post')

方式2:在类的投诉,加入csrf_exempt无效,还是报错:Forbidden (403)
	1.先打开settings.py配置文件中下面这行代码:即不用注释
	'django.middleware.csrf.CsrfViewMiddleware',
	2.在类的头上加了装饰器,但是还是无效
	@method_decorator(csrf_exempt, name='post')
	class Login(View):
	    # 不让post方法做验证
	    def post(self, request):
	        print('post')
	        return HttpResponse('post')

方式3:CBV的验证只有在dispatch函数上加装饰器,需要验证的函数才能通过验证
	class Login(View):
    	@method_decorator(csrf_exempt)
	    def dispatch(self, request, *args, **kwargs):
	        return super(Login, self).dispatch(request, *args, **kwargs)
	    
	    # 不让post方法做验证
	    def post(self, request):
	        print('post')
        return HttpResponse('post')

注意:在settings.py配置文件中注释下面这行代码:
	#'django.middleware.csrf.CsrfViewMiddleware',
	然后,对三种方式进行验证csrf_protect,都可以

CBV针对于csrf_exempt:只有第三张方式才生效,其余两种方式不行
CBV针对于csrf_protect:三种方式都可以

# @method_decorator(csrf_protect,name='post') # 第二种方式也行
class Login(View):
    @method_decorator(csrf_protect)  # 第三种方式可以
    def dispatch(self, request, *args, **kwargs):
        return super().dispatch(request, *args, **kwargs)
    # 不让post方法做验证
    # @method_decorator(csrf_protect)  # 第一种方式行
    def post(self, request):
        print("post")
        return HttpResponse("post")

二、Auth模块的使用

Auth模块是什么?
	Auth模块是Django自带的用户认证模块:

我们在开发一个网站的时候,无可避免的需要设计实现网站的用户系统。此时我们需要实现包括用户注册、用户登录、用户认证、注销、修改密码等功能,这还真是个麻烦的事情呢。

Django作为一个完美主义者的终极框架,当然也会想到用户的这些痛点。它内置了强大的用户认证系统–auth,它默认使用 auth_user 表来存储用户数据。

注意事项:
	在执行数据库迁移命令的时候,会自动生成一个默认的表,其中有auth_开头的很多表
	auth_user表的作用:djagno自带的后台管理系统所依赖的数据就在这张表中
	默认情况下,auth_user表是空表,没有用户名和密码,因此我们需要自己创建用户数据
	需要创建一个超级管理员账号才能登录
	
'''
创建超级管理员命令:
	python manage.py createsuperuser

在配置文件settings.py中修改语言为中文和时区:
# 语言
LANGUAGE_CODE = 'zh-hans'
# 时区
TIME_ZONE = 'Asia/Shanghai'
USE_I18N = True
USE_L10N = True
USE_TZ = False

'''


三、Auth模块的相关方法

登录功能、注册功能、修改密码、退出系统、认证功能等学习如何使用


# http://127.0.0.1:8000/accounts/login/?next=/order/
# @login_required # :http://127.0.0.1:8000/accounts/login/?next=/order/
'''
    当局部和全局都存在的时候,按局部的
    如果局部没有,按照全局的
'''
@login_required(login_url='/order/login/')  # 局部设置
def order(request):
    pass

###################配置文件中全局配置

LOGIN_URL = '/login/' # 全局配置

'''
如果没有登录则 跳转到 http://127.0.0.1:8000/accounts/login/?next=/order/
但是若加了装饰器,则跳转到指定的路由页面

在settings.py配置文件中全局配置,
LOGIN_URL = '/login/'

当局部和全局都在的时候,按局部的,若局部没有,则按全局的
'''
@login_required(login_url='/login/')  # 局部设置登录
def order(request):
    # 验证用户是否已经登录认证
    print(request.user.is_authenticated)  # True

    # 若加了@login_required装饰器,则下面的判断不需要
    # if request.user.is_authenticated:
    #     # 处理登录之后的逻辑
    #     pass
    # else:
    #     # 没有登录,跳转登录页面
    #     pass

    return HttpResponse('order')


def order1(request):
    return HttpResponse('order')
    
---------------------------------------------------------------------------------------

auth模块的后端登录代码:
from django.contrib import auth


def login(request):
    if request.method == 'POST':
        # 1.接收前端传过来的数据
        username = request.POST.get('username')
        password = request.POST.get('password')

        # 2.验证用户名和密码是否正确
        # 2.1 去哪个表中查询数据
        # 2.2 使用这张表中的哪个字段来比较
        '''
            这里的登录,我们使用auth模块,登录的时候所使用的表是auth_user表
        '''

        # def authenticate(request=None, **credentials):return user 需要关键字传参
        user_obj = auth.authenticate(request, username=username, password=password)  # request.session['username'] = user_obj.usernane
        '''返回值是登录成功之后的用户对象'''
        print(user_obj)  # linda
        print(user_obj.username)  # linda
        print(user_obj.password)  # pbkdf2_sha256$150000$auQyjuifJ0ie$I8uTuxyATU6FubswdMCTiL2+Hg+5sqzkvZruPmPdlZ0=
        '''
            注意事项1:传递参数的时候,用户名和密码必须同时传入
        '''
        # if user_obj:
        #     # 保存用户的状态:cookie  session
        #     request.session['username'] = user_obj.username
        #     request.session['id'] = user_obj.id
        '''
            注意事项2:由于上面使用了auth模块,在此不建议这样写,auth模块都提供有相应的方法
            
            要么全部使用auth模块的方法,要么全部自己写,不建议混合使用
        '''

        # 3.使用auth模块提供的方法
        auth.login(request, user_obj)
        '''
            只要写了auth.login,那么就可以在全局有任何request的地方使用request.user拿到用户对象
        '''

        return redirect('/home/')

    return render(request, 'login.html')

登录页面前端代码

DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Documenttitle>
    <style>
        body {
            {#background: url('https://pic2.zhimg.com/3ae866e7992a94069c7e0c417aac807d_r.jpg') no-repeat;#}
            background: url('https://img0.baidu.com/it/u=741268616,1401664941&fm=253&app=138&size=w931&n=0&f=JPEG&fmt=auto?sec=1691859600&t=5c5bee3052ecec363c1ecc2eea9ac3f7') no-repeat;
            background-size: 100% 130%;
        }

        #login_box {
            width: 20%;
            height: 400px;
            background-color: #00000060;
            margin: auto;
            margin-top: 10%;
            text-align: center;
            border-radius: 10px;
            padding: 50px 50px;
        }

        h2 {
            color: #ffffff90;
            margin-top: 5%;
        }

        #input-box {
            margin-top: 5%;
        }

        span {
            color: #fff;
        }

        input {
            border: 0;
            width: 60%;
            font-size: 15px;
            color: #fff;
            background: transparent;
            border-bottom: 2px solid #fff;
            padding: 5px 10px;
            outline: none;
            margin-top: 10px;
        }

        button {
            margin-top: 50px;
            width: 60%;
            height: 30px;
            border-radius: 10px;
            border: 0;
            color: #fff;
            text-align: center;
            line-height: 30px;
            font-size: 15px;
            background-image: linear-gradient(to right, #30cfd0, #330867);
        }

        #sign_up {
            margin-top: 45%;
            margin-left: 60%;
        }

        a {
            color: #b94648;
        }
    style>
head>

<body>
<div id="login_box">
    <h2>登录页面h2>
    <form action="" method="post">
        <div id="input_box">
            <input type="text" placeholder="请输入用户名" name="username">
        div>
        <div class="input_box">
            <input type="password" placeholder="请输入密码" name="password">
        div>
        <button>提交button>
{#        <input type="submit" value="提交">#}
        <br>
    form>
div>
body>
html>


四、Auth模块之退出系统

def logout(request):
    # 清除cookie或者session
    auth.logout(request)
    return redirect('/home/')
    

六、Auth模块之修改密码功能

1.验证老密码是否正确
is_right = request.user.check_password(old_password)

2.修改密码
request.user.set_password(new_password) # 这种写法没有真正的操作数据库
request.user.save()  # 但是执行了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')
        re_password = request.POST.get('re_password')

        # 先验证两次密码是否输入一致
        if new_password == re_password:
            # 验证老密码是否正确
            is_right = request.user.check_password(old_password)
            if is_right:
                # 修改密码
                # 方式1:这种写法没有真正的操作数据库
                request.user.set_password(new_password)
                # 方式1需要保存一下才能修改成功到数据库
                request.user.save()
                return redirect('/home/')

    return render(request, 'set_password.html', locals())


前端代码:
<div id="login_box">
    <h2>修改密码</h2>
    <form action="" method="post">
        {% csrf_token %}
        <div id="input_box">用户名:
            <input type="text" name="username" readonly value="{{ request.user.username }}">
        </div>
        <div class="input_box">旧密码:
            <input type="password" placeholder="请输入旧密码" name="old_password">
        </div>
        <div class="input_box">新密码:
            <input type="password" placeholder="请输入新密码" name="new_password">
        </div>
        <div class="input_box">请确认:
             <input type="password" placeholder="确认新密码" name="re_password">
        </div>
        <button>提交</button>
{#        #}
        <br>
    </form>
</div>

七、Auth模块之注册功能

'''
入库的三种方式:
    方式1:自动入库到auth_user表,但是密码是明文密码,登录的时候是经过加密处理的,则登录不上
    User.objects.create(username=username, password=password)
    
    方式2:密码是密文入库
    User.objects.create_user(username=username, password=password)
    
    方式3:创建超级用户,并且密码是密文存入,但是必须指定邮箱,否则报错
    User.objects.create_superuser(username=username, password=password, email='[email protected]')
'''

from django.contrib.auth.models import User


def register(request):
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')

        # 入库
        # 方式1:自动入库到auth_user表,但是密码是明文密码,登录的时候是经过加密处理的,则登录不上
        # User.objects.create(username=username, password=password)

        # 方式2:创建普通用户,密码是密文入库
        # User.objects.create_user(username=username, password=password)

        # 方式3:创建超级用户,并且密码是密文存入,但是必须指定邮箱,否则报错
        User.objects.create_superuser(username=username, password=password, email='[email protected]')

        return redirect('/login/')

    return render(request, 'register.html')

八、扩展默认的auth_user表

默认情况下使用的就是auth_user的默认字段
扩展我们自己的字段

前提是:所有的模型类都继承
from django.contrib.auth.models import AbstractUser

现在是要在auth_user表的基础上扩展字段,不要继承了models.Model

**************************************************************************
注意:
	扩展之后需要在配置文件(settings.py)中加一句话
	AUTH_USER_MODEL = '应用名.表名'
	eg:
		AUTH_USER_MODEL = 'app01.UserInfo'

-------------------------------------------------------------------------------------

注意:
	"""在扩展表之前数据库不能够迁移,扩展这个表需要在迁移数据库之前做"""

问:如果你迁移了,还想扩展怎么办?
	1. 换库
	2. 需要删除很多个应用的migrations文件夹
注意:
	迁移报错的时候,有可能会用到下面这句代码:
	python manage.py migrate myapp --fake

---------------重点:扩展表之后发生的变化-------------------
"""
	扩展表之后发生的变化:
		1. 原来的auth_user表不存在了,换成你自己新建的表名了
		2. 原来的auth_user表中的字段还都在,然后多了自己扩展的字段
		3. 继承的类要发生改变AbstractUser
		4. 在配置文件中加入下面一句话:
			AUTH_USER_MODEL = 'app01.UserInfo'
			AUTH_USER_MODEL = '应用名.类名'
		5. 扩展之后还是按照原来的auth_user表使用
		6. auth模块中的数据还是你扩展的表
		7. 扩展之前别迁移.
"""

--------------------------------------------------------------------
案例:
因为之前迁移过了,所以我选择换库:从sqlite3---->mysql

1.在settings.py配置文件中把数据库换成MySQL:
'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'db22',
        'HOST': '127.0.0.1',
        'PORT': 3306,
        'USER': 'root',
        'PASSWORD': 'root',
        'CHARSET': 'utf8'
    },
2.扩展表的字段:先导入AbstractUser,让扩展表继承AbstractUser
from django.contrib.auth.models import AbstractUser
class UserInfo(AbstractUser):
    phone = models.CharField(max_length=64)
    # 头像
    avatar = models.CharField(max_length=64)
3.迁移
python manage.py makemigrations
python manage.py migrate

你可能感兴趣的:(python01,django,csrf,django,python)