一、csrf跨站请求的相关装饰器
python
复制代码
'''
django.middleware.csrf.CsrfViewMiddleware
Django中有一个中间件对csrf跨站做了验证,我只要把csrf的这个中间件打开,
那就意味着所有的方法都要被验证
'''
在所有的视图函数中:
只有几个视图函数做验证
只有几个函数不做验证
csrf_protect: 哪个视图函数加了这个装饰器,这个函数就会做验证
csrf_exempt:哪个视图函数加了这个装饰器,这个函数就不会做验证
-------------------------------------------------------------------------------
注意:加入装饰器验证csrf,先导入下面这行代码:
from django.views.decorators.csrf import csrf_exempt,csrf_protect
一、FBV模式下:
情境1:
1.先在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函数不需要
情境2:
1.先打开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验证。
情境3:
1.在打开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模块的使用
python
复制代码
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模块的相关方法
python
复制代码
登录功能、注册功能、修改密码、退出系统、认证功能等学习如何使用
# 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')
登录页面前端代码
html
复制代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<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模块之退出系统
python
复制代码
def logout(request):
# 清除cookie或者session
auth.logout(request)
return redirect('/home/')
六、Auth模块之修改密码功能
python
复制代码
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>
{# <input type="submit" value="提交">#}
<br>
</form>
</div>
七、Auth模块之注册功能
python
复制代码
'''
入库的三种方式:
方式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='123@qq.com')
'''
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='123@qq.com')
return redirect('/login/')
return render(request, 'register.html')
八、扩展默认的auth_user表
python
复制代码
默认情况下使用的就是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