昨日内容回顾
# 作用:就是保存用户信息,保存一系列数据,还可以做缓存 保留一段时间
# session是基于cookie工作的
1. 数据是保存在服务端
2. 存储的介质:
01 文件
02 数据库
03 redis
3. 如果以后项目中使用了负载均衡,注意考虑是否有session共享的问题
# 如何使用session:
1. 设置session
request.session['username'] = 'aaa'
request.session['id'] = 111
'''
1. 生成一个随机字符串,
2. 保存数据到数据库中
session_key session_data
3. 把数据加密处理之后保存的。
'''
2. 获取session
request.session['username']
# session设置的时候,是被加密的,获取出来的session值是明文的
'''
1. 先拿到sessionid => session中的随机字符串 session_key
2. 会拿着sessionid的值去表中查询
如果有数据,进行反解密,在把数据封装到request.session中,因此,我们直接可以通过request.session['id'] 取值
'''
# 以上操作是在中间件中处理的,sessionmiddleware
# 如何设置session的过期时间
request.session.set_expity(120)
# 设置会话Session和Cookie的超时时间
'''
request.session.set_expiry(value)
* 如果value是个整数,session会在些秒数后失效
* 如果value是个datatime或timedelta,session就会在这个时间后失效
* 如果value是0,用户关闭浏览器session就会失效
* 如果value是None,session会依赖全局session失效策略
'''
# FBV:直接在函数的头上面添加装饰器的名称
# CBV:添加装饰器与FBV添加装饰器是有区别的
cbv添加装饰器需要借助于一个装饰器
from django.utils.decorators import method_dectorator
'''drf:django rest framework => '''
from django.views import View
'''
请求方式:8种, get, post,
options
put
patch
在前后端分离项目中,会出现跨域问题 简单请求,复杂请求
'''
@method_decorators(login_auth, 'get')
@method_decorators(login_auth, 'post')
@method_decorators(login_auth, 'patch')
class IndexView(View):
# 重写父类的方法
@method_decorators() # 给IndexView所有的方法添加装饰器
def dispatch(self, request, *args, **kwargs):
# 依据:mro列表
return super().dispatch(request, *args, **kwargs):
@method_decorators(login_auth)
def get(self, request):
return HttpResponse('ok')
# 1. 中间件的位置在哪里?在路由层之前
django提供了7个中间件,在配置文件中,我们是可以查询这七个中间件的源码的
# 2. csrf的中间件, 针对于post请求的提交做csrf的校验
# 3. 支持我们自定义中间件
3.1 在任意一个应用下,创建一个py文件
3.2 写一个类,类里面有2个方法,类必须继承middlewaremixin
3.3 去配置文件中注册中间件
# 需要我们掌握的是2个方法:
1. process_request
# 请求来的时候,会按照中间的注册顺序,依次从上往下执行
2. procesS_resposne
# 请求走的时候,会按照中间件的注册顺序,依次从下往上执行。
'''
视图函数在所有中间件的process_request之后,所有中间件的process_response之前
'''
# 如果我们在某一个中间件中的process_reqeust返回了值,之后的中间件都不在走了,然后再走同级别的process_response方法
# 以下3个都不重要(了解)
3. process_view
4. process_template
5. process_excption
# 使用场景:
1. 对全栈做权限校验
2. 频率限制
3. 认证
今日内容概要
- csrf跨站请求
- csrf的处理(提供的有相关装饰器)
- Auth模块
- B端产品(business,eg:crm,)
- C端产品(consumer面向用户的,eg:淘宝,京东,租号玩)
内容详细
1. csrf跨站请求
# 背景:
钓鱼网站
'''
英语4级报名网站为例
你要在这个网站要付费,你去的这个网站是一个冒牌的网站,就去冒牌网站里面付费了,钱付到了冒牌网站,但是没有报名成功
'''
会出现在form表单中,action参数:朝后端发送的地址
# 怎么解决这个问题?
csrf是针对与post请求的才会做验证
"""
token相关的报错:
一般都是一个串:秘钥 私钥 公钥...
"""
# 两种解决方式
# views.py中添加功能:
def index(request):
return render(request, 'index.html')
# urls.py中添加路由:
url(r'^index/', views.index),
# 新建index.html文件:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>
{#<form action="" method="post">#}
{# {% csrf_token %} {# 解决csrf_token相关报错 方法一 #}
{# <p>username<input type="text" name="username"></p>#}
{# <p>password<input type="text" name="password"></p>#}
{# <input type="submit">#}
{#</form>#}
<button class="btn">ajax</button>
<script> {# 解决csrf_token相关报错 方法二 #}
$('.btn').click(function () {
$.ajax({
url: '',
type: 'post',
{#data:{'a':1, 'csrfmiddlewaretoken':$('[name="csrfmiddlewaretoken"]').val()}, {# 有form表单这样写 #}
data: {'a': 1, 'csrfmiddlewaretoken': '{{ csrf_token }}'}, {# 没有form表单这样写 #}
success: function () {
}
})
})
</script>
</body>
</html>
2. csrf相关装饰器
# 如果使用中间件限制的话,就会限制全局的,要么全部限制,要么全部不限制
# 两种情况
只有index函数需要验证,其他的不需要验证
只想让home函数不验证,其他的都需要验证
# 提供了2个装饰器
csrf_protect: 需要验证
csrf_exempt: 不需要验证
'''按照FBV和CBV的使用即可'''
# 在views.py中测试:
from django.views.decorators.csrf import csrf_exempt, csrf_protect
from django.utils.decorators import method_decorator
from django.views import View
'''
针对CBV:
csrf_protect的三种方式都是可以的
csrf_exempt前两种方式都不行,只有第三种方式可以的
'''
# @method_decorator(csrf_protect, 'post') # 2.针对CBV需要验证 方式二
# @method_decorator(csrf_exempt, 'post') # 5.这种方式也不行
# class IndexView(View):
# @method_decorator(csrf_protect) # 1.针对CBV需要验证 方式一
# @method_decorator(csrf_exempt) # 4.这种方式不可以
# def post(self, request):
# return HttpResponse('post')
class IndexView(View):
# @method_decorator(csrf_protect) # 3.针对CBV需要验证 方式三
@method_decorator(csrf_exempt) # 6.这种方式是可以的
def dispatch(self, request, *args, **kwargs):
return super().dispatch(request, *args, **kwargs)
def post(self, request):
return HttpResponse('post')
3. Auth模块
# 迁移数据库会有一个表生成,auth_user
# django项目创建完后之后,会有一个默认的路由,admin/
# admin/是django默认提供的后台管理界面
# 访问admin/
登录参照的数据就是从auth_user表中来,前提是必须是超级管理员
# 如何创建超级管理员?
python3 manage.py createsuperuser
# auth模块实现登录功能
# 在views.py中测试:
def home(request):
return render(request, 'home.html')
from django.contrib import auth
def login(request):
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
# 1.去哪个表查询登录数据:auth_user
# 2.密码如何比对
"""
注意事项:
用户名与密码必须两者同时传入
"""
obj = auth.authenticate(request, username=username, password=password)
# print(obj) # None 密码不正确返回的值 结果是当前对象
# print(obj) # root 密码正确返回的值 结果是当前对象
# print(obj.username)
# print(obj.password)
if obj:
# 保存用户信息 auth模块有全套功能需要使用
auth.login(request, obj) # 相当于保存了用户信息
"""
一旦执行了上面的这句话 就可以在全局任何地方 通过request.user 拿到用户对象
"""
return redirect('/home/')
return render(request, 'login.html')
# login.html内容:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>
<form action="" method="post">
<p>username:<input type="text" name="username"></p>
<p>password:<input type="text" name="password"></p>
<input type="submit">
</form>
</body>
</html>
# urls.py添加路由:
url(r'^home/', views.home),
url(r'^login/', views.login),
# home.html写入:
body标签内:<h1>home页</h1>
# auth模块验证是否登录(装饰器)
from django.contrib.auth.decorators import login_required
"""
登录装饰器跳转的地址有两种:
1.局部的
@login_required(login_url=login)
2.全局的 在settings.py文件中配置
LOGIN_URL = '/login/'
如果同时存在局部的和全局的 那么优先访问 局部 的地址
"""
@login_required # 判断是否登录装饰器 代替了下面的 if判断
def func(request):
# 必须登录之后才能访问
print(request.user) # AnonymousUser 未登录状态下访问
print(request.user) # root 用户名 登录状态下访问
print(request.user.is_authenticated()) # 验证是否登录 False True
# if request.user.is_authenticated():
# return HttpResponse('func')
# else:
# return redirect('/login/')
# 添加路由:
url(r'^func/', views.func),
# auth模块实现修改密码
@login_required
def set_pwd(request):
if request.method == 'POST':
old_pwd = request.POST.get('old_pwd')
new_pwd = request.POST.get('new_pwd')
again_pwd = request.POST.get('again_pwd')
# 1. 先判断两次密码输入是否一致
if new_pwd == again_pwd:
# 2. 校验老密码是否正确
is_right = request.user.check_password(old_pwd)
print(is_right) # 返回的是布尔值
if is_right:
# 3. 修改密码
request.user.set_password(new_pwd) # 这句话 并没有把密码修改到数据库里 只是修改了password密码的属性
request.user.save() # 这句话才是真正的操作数据了
return redirect('/home/')
return render(request, 'set_pwd.html')
# 添加路由:
url(r'^set_pwd/', views.set_pwd),
# auth模块实现注销功能
def logout(request):
# 清空cookie和session
# request.session.delete()
# request.session.flush()
auth.logout(request)
return redirect('/login/')
# 添加路由:
url(r'^logout/', views.logout),
# auth模块实现注册用户功能
from django.contrib.auth.models import User # 相当于使用 auth_user表
def register(request):
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
# 数据入库
# User.objects.create(username=username, password=password) # 密码是明文的
User.objects.create_user(username=username, password=password) # 密码是加密的
return redirect('/home/')
# 添加路由:
url(r'^register/', views.register),