赞
踩
发展史:
1. 网站不保存用户信息,所有用户的访问返回结果都一样.(eg:新闻,博客)
2. 需要保存用户信息,所有用户的放回都是单独的.(eg:淘宝)
以登入功能为例:
如果不保存用户登入状态,也就意味着用户每次访问网站都需要重复的输入用户名密码.
当用户第一次登入成功之后,将用户的名与密码返回给浏览器,在本地保存,
之后在访问这个网站的时候,浏览器会自动将用户名个密码发给服务器,服务自动校验.
cookie:服务端保存在客户端浏览器上的信息都可以称为cookie.
它的表现形式一帮是k:v键值对(可以有多个)
早期这种方式非常大的安全隐患.
优化:
当用户登入成功之后,服务端产生一个随机字符串,交由客户端浏览器保存,
之后访问服务端的时候,都带着该随机字符串.服务端去数据库中比对是否有对应的随机字符串
从而获取到对应的用户信息.
如果截取到该字符串,那么可以冒充这个用户,还是有安全隐患.
在web领域没有绝对的安全,也没有绝对的不安全.
session:数据是保存在服务端的并且他的表现形式一帮都是k:v键值对(可以有多个)
session 是基于cookie工作的(大部分的保存用户状态的操作都是需要使用到cookie).
ps:
token: session虽然是保存在服务的,但是经不住量大.
服务端不再保存数据,登入之后将一段信息进行加密处理,
将加密之后的密文结果拼在信息后面保存到浏览器,
浏览器下次访问的时候带着该信息,
服务端字段切去前面一段信息在再次使用自己的加密算法跟计算机尾部的密文比对.
jwt认证:(使用多)
三端信息
虽然cookie是服务端告诉浏览器需要保存内容,但是客户端浏览器可以选择拒绝保存.
如果禁止了,只要是需要记录用户状态的网站登陆功能都无法使用.
# 视图函数的返回回值
return HttpResponse()
return render()
return redirec()
# 如果需要操作Cookit 需要变形操作
HttpResponse_obj = HttpResponse()
return HttpResponse_obj
render_obj = render()
return render_obj
redirec_obj = redirec()
return redirec_obj
# 设置cookie
obj.set_cookit(key, value)
# 获取 cookie()
request.COOKIES.get(key)
# 超时都是以秒为单位
为cookie设置一个超时时间,5秒到期
obj.set_cookit(key, value, max_age = 5)
# 针对ie浏览器
obj.set_cookit(key, value, expires=)
# 删除cookie
obj.delete_cookie(key)
写一个登入功能.
登入之后进入到主页
from django.conf.urls import url
from django.contrib import admin
# 0. 导入视图层
from app01 import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
# 1. 登入功能
url(r'^login/', views.login),
# 2. 主页
url(r'^home/', views.home)
]
# 登入功能 views.py # 0. 导入 Django 三板斧 from django.shortcuts import render, redirect, HttpResponse # Create your views here. # 1. forms 组件定义 from django import forms class MyForms(forms.Form): # 名称 username = forms.CharField( label='名称', min_length=3, max_length=6, error_messages={ 'min_length': '名称过短', 'max_length': '名称过长', 'required': '名称不能为空' }, widget=forms.widgets.TextInput( attrs=({'class': 'form-control'}) ) ) # 密码 password = forms.CharField( label='密码', min_length=3, max_length=11, error_messages={ 'min_length': '密码过短', 'max_length': '密码过长', 'required': '名称不能为空' }, widget=forms.widgets.PasswordInput( attrs=({'class': 'form-control'}) ) ) # 2. 登入函数 def login(request): # 2.1 forms对象 forms_obj = MyForms() # 2.3 判断请求方式 if request.method == 'POST': print(request.POST) # 2.4 检验密码 字符串类型比对 if request.POST.get('username') == 'kid' and request.POST.get('password') == '123': return redirect('/home/') else: forms_obj = MyForms(request.POST) # 2.2 返回登入页面 和 forms组件对象 return render(request, 'login.html', locals()) # 3. 主页 def home(request): return render(request, 'home.html')
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>登入功能</title> <!--0. 动态获取静态文件名称 --> {% load static %} <!--1. 导入jQuery js 文件--> <script src="{% static 'js/jquery-3.6.0.min.js' %}"></script> <!--2. 导入 bootstrap css 文件--> <link rel="stylesheet" href="{% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}"> <!--3. 导入 bootstrap js 文件--> <script src="{% static 'bootstrap-3.3.7-dist/js/bootstrap.min.js' %}"></script> </head> <body> <div> <!--4. form表单 post请求 前端不验证 --> <form action="" method="post" novalidate> {% for form in forms_obj %} <p>{{ form.label }}:{{ form }} <span style="color: red;">{{ form.errors.0 }}</span></p> {% endfor %} <input type="submit"> </form> </div> </body> </html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>主页</title>
</head>
<body>
<div>
我是主页
</div>
</body>
</html>
0. 浏览器中输入 127.0.0.1/login 登入页面中 输入 名称 密码 进去主页.
1. 浏览器中输入 127.0.0.1/home 直接访问.
在登入验证处设置 cookie 信息
# 2.5 检验密码 字符串类型比对
if username == 'kid' and password == '123':
# 2.6 cookie 操作
"""
1. 生成对象
2. 设置cookie
3. 返回对象
"""
redirect_obj = redirect('/home/')
redirect_obj.set_cookie('username', 'kid666')
return redirect_obj
# 2. 登入函数 def login(request): # 2.1 forms对象 forms_obj = MyForms() # 2.3 判断请求方式 if request.method == 'POST': print(request.POST) # 2.4 获取post提交的数据 username = request.POST.get('username') password = request.POST.get('password') # 2.5 检验密码 字符串类型比对 if username == 'kid' and password == '123': # 2.6 cookie 操作 """ 1. 生成对象 2. 设置cookie 3. 返回对象 """ redirect_obj = redirect('/home/') redirect_obj.set_cookie('username', 'kid666') return redirect_obj else: forms_obj = MyForms(request.POST) # 2.2 返回登入页面 和 forms组件对象 return render(request, 'login.html', locals())
* 设置cookie后在测试, 测试前对cookie清除.
0. 浏览器中输入 127.0.0.1/login 登入页面中 输入 名称 密码 进去主页.
查看到cookie中有数据.
cookie 中有数据
1. 浏览器中输入 127.0.0.1/home 直接访问.
cookie 是没有数据的. 显示非法访问
cookie数据被保存到request中
通过request.COOKIES.get('key') 获取值
如果能获取到数据那说明是通过登入页面正常输入账户密码进入主页的,
不然就直接访问的.
# 3. 主页
def home(request):
# 3.2 获取request中的cookie数据
if request.COOKIES.get('username') == 'kid666':
# 3.1 返回主页
return render(request, 'home.html')
else:
# 3.2 返回提示信息
return HttpResponse('非法访问')
0. 浏览器中输入 127.0.0.1/login 登入页面中 输入 名称 密码 进去主页.
cookie 中有数据
1. 浏览器中输入 127.0.0.1/home 直接访问.
cookie 是没有数据的.
如果有多个需要验证才能进入的页面,就可以制作一个校验信息的登入装饰器.
# urls.py
# 3. 需要验证才能登入的网页1
url(r'^index1', views.),
# 4. 需要验证才能登入的网页2
url(r'^index2', views.index2),
# 5. 需要验证才能登入的网页3
url(r'^index3', views.index2)
# 4. 登入验证 def verification(func): def inner(request, *args, **kwargs): # 验证cookie中的数据 if request.COOKIES.get('username') == 'kid666': res = func(request, *args, **kwargs) return res else: return redirect('/login/') return inner # 5. 需要验证才能登入的网页1 @verification def index1(request): return HttpResponse('需要验证才能登入的网页1') # 6. 需要验证才能登入的网页2 @verification def index2(request): return HttpResponse('需要验证才能登入的网页2') # 7. 需要验证才能登入的网页3 @verification def index3(request): return HttpResponse('需要验证才能登入的网页3')
在没有cookie中没有数据的时候是无法直接进入到
index1 index2 index3 的页面
被重定向到login功能中,要求登入...
输入正确的用户和密码.
只有当cookie有了数据,并且数据符合要求,
就能够直接访问 index1 index2 index3 的页面.
现在存在的问题是 cookie中没有数据 进入 127.0.0.1/index1 2 3
跳转到登入页面,成功登入之后,应该返回用户之前想要访问的页面去.
而不是进入了home页面.
request.path
提供相对于根目录的url相对路径,不包含参数。它的输出是一个字符串
/index1
request.path_info
提供相对于根目录的url相对路径,不包含参数。它的输出也是一个字符串,与request.path相同.
/index1
request.get_full_path()
获取包含完整参数的相对于根目录的相对url路径。
/index1/?name=kid
request.build_absolute_uri()
该方法用于获取带域名的url绝对路径, 是一个字符串.
http://127.0.0.1:8000/index1/?name=kid
# 进入登入页面的时候携带我们要访问的url
target_url = request.get_full_path()
return redirect('/login/?next=%s' % target_url)
# 4. 登入验证
def verification(func):
def inner(request, *args, **kwargs):
# 4.1 验证cookie的数据
if request.COOKIES.get('username') == 'kid666':
# 4.1 验证通过执行被装饰的函数 index 1 2 3
res = func(request, *args, **kwargs)
return res
else:
# 4.2 获取输入的地址
target_url = request.get_full_path()
return redirect('/login/?next=%s' % target_url)
return inner
当前的form表单的提交方式是post
<!--4. form表单 post请求 前端不验证 -->
<form action="" method="post" novalidate>
# 2. 登入函数 def login(request): # 2.1 forms对象 forms_obj = MyForms() # 2.3 判断请求方式 if request.method == 'POST': print(request.POST) # 2.4 获取post提交的数据 username = request.POST.get('username') password = request.POST.get('password') # 2.5 检验密码 字符串类型比对 if username == 'kid' and password == '123': # 2.6 获取根目录地址 target_url = request.GET.get('next') print(target_url) # 2.7 cookie 操作 如果获取到地址就把这个地址作为参数,没有获取到地址就访问到主页. if target_url: redirect_obj = redirect(target_url) else: redirect_obj = redirect('/home/') redirect_obj.set_cookie('username', 'kid666') return redirect_obj else: forms_obj = MyForms(request.POST) # 2.2 返回登入页面 和 forms组件对象 return render(request, 'login.html', locals())
# urls.py
# 6. 注销
url(r'^logout/', views.logout)
# views.py
# 5. 需要验证才能登入的网页1
@verification
def index1(request):
return render(request, 'index1.html')
# views.py
# 8. 注销 (只有登入的用户才能注销) 注销之后退回到登入页面中去
@verification
def logout(request):
# 8.1 生成对象
redirect_obj = redirect('/login/')
# 8.2 清除cookie中指定的数据
redirect_obj.delete_cookie('username')
# 8.3 返回对象
return redirect_obj
<li><a href="/logout/">退出登入</a></li> 绑定logout
<!-- index.html --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>index1</title> <!--0. 动态获取静态文件名称 --> {% load static %} <!--1. 导入jQuery js 文件--> <script src="{% static 'js/jquery-3.6.0.min.js' %}"></script> <!--2. 导入 bootstrap css 文件--> <link rel="stylesheet" href="{% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}"> <!--3. 导入 bootstrap js 文件--> <script src="{% static 'bootstrap-3.3.7-dist/js/bootstrap.min.js' %}"></script> </head> <body> <div> <!--4. 导航条--> <nav class="navbar navbar-default"> <div class="container-fluid"> <!-- Brand and toggle get grouped for better mobile display --> <div class="navbar-header"> <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="navbar-brand" href="#">Brand</a> </div> <!-- Collect the nav links, forms, and other content for toggling --> <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1"> <ul class="nav navbar-nav"> <li class="active"><a href="#">Link <span class="sr-only">(current)</span></a></li> <li><a href="#">Link</a></li> <li class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Dropdown <span class="caret"></span></a> <ul class="dropdown-menu"> <li><a href="#">Action</a></li> <li><a href="#">Another action</a></li> <li><a href="#">Something else here</a></li> <li role="separator" class="divider"></li> <li><a href="#">Separated link</a></li> <li role="separator" class="divider"></li> <li><a href="#">One more separated link</a></li> </ul> </li> </ul> <form class="navbar-form navbar-left"> <div class="form-group"> <input type="text" class="form-control" placeholder="Search"> </div> <button type="submit" class="btn btn-default">Submit</button> </form> <ul class="nav navbar-nav navbar-right"> <li><a href="#">Link</a></li> <li class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">状态<span class="caret"></span></a> <ul class="dropdown-menu"> <li><a href="/logout/">退出登入</a></li> </ul> </li> </ul> </div><!-- /.navbar-collapse --> </div><!-- /.container-fluid --> </nav> </div> <div> <div class="jumbotron"> <h1>Hello, world!</h1> <p>...</p> <p><a class="btn btn-primary btn-lg" href="#" role="button">Learn more</a></p> </div> </div> </body> </html>
0. 浏览器中访问 127.0.0.1:8000/index1 (清除cookie)
1. 触发登入检验 转到 login 登入页面中
2. 提交form表单的数据 (post请求)
3. 账户密码正确 设置cookie的值
4. 获取get后面携带的路径
5. 访问该路径
6. 点击退出按键
7. 清除cookie 并返回到 login 页面
session数据是保存在服务端的,给用户返回的是一个sessionid(键的随机字符串).
在默认的情况下操作session的时候需要一张 django_session表.
数据库迁移命令的时候django会自动创建.
1. 设置值 request.session{'key'} = value 2. 获取值 request.session.get('key') 3. 设置过期时间 (先设值之后设置过期时间) request.session.set_expiry() 设置过期时间 括号内可以放四种类型的参数: 1.xx秒 整数 2.日期对象 到指定日期 3.数字零 浏览器关闭立刻失效 4.不写 失效时间取决于django内部全局session默认的失效时间 django默认的session默认的过期时间是14天,但是也可以认为的修改它 4. 清除值 request.session.delete() 只删服务端的 客户端不删 request.session.flush() 浏览器和服务端都清空 一般使用这个
需要一张默认的表,
直接执行数据库迁移命令.
python manage.py makemigrations
python manage.py migrate
I:\备份\test\day08>python manage.py makemigrations
No changes detected # 没事
I:\备份\test\day08>python manage.py migrate
···ok
session 放在服务端的,位置可以有多种选择
1.MySQL
2.文件
3.redis
···
下载驱动后点测试,测试成功之后点ok.
# urls.py
# 7. session 设置值
url(r'^set_session/', views.set_session),
# views.py
# 9. 设置值
def set_session(request):
# 9.1 把session的值添加到request中
request.session['username'] = 'kid666'
# 9.2 返回值
return HttpResponse('set_session执行了')
浏览器中访问 127.0.0.1:8000/set_session
session的值也是在CooKie中查看
名称为 session 值是随机字符串
request.session['username'] = 'kid666'
内部发生的事情:
1. django内部会自动生成一个随机字符串
2. django自动将随机字符串和对应的数据存储到django_session表中
2.1 先在内存中产生操作数据的缓存
2.2 经过django中间件的时候才真正的操作数据库
3.将产生的随机字符串返回给客户端保存(键)
# urls.py
# 8. 获取 session 中的值
url(r'^get_session', views.get_session)
# views.py
# 10. 获取值
def get_session(request):
# 9.1 获取session中的值
value = request.session.get('username')
print(value) # kid666
# 9.2 返回值
return HttpResponse('get_session执行了')
print(request.session.get('username'))
内部发生的事情
1.自动从浏览器请求中获取session对应的随机字符串
2.拿着该字符串去django__session表中查询对应的数据
3.如果比对上了,则将对应的数据取出并以字典的形式封装到request.session中
如果比对不上request.session.get('') 返回的是None
# views.py
# 9. 设置值
def set_session(request):
# 9.1 把session的值添加到request中
request.session['studio1'] = 'Python'
request.session['studio2'] = 'MySQL'
request.session['studio3'] = 'Linux'
# 9.3 返回值
return HttpResponse('set_session执行了')
上面的值存放在表中的一条数据中.
django_session表中数据是取决于浏览器的
同一个计算机上,同一浏览器只有一条数据生效.为了节省服务端资源.
(当session过期的时候会出现多条数据对应一个浏览器, 短暂的存在,会自动清理,也可以手动清理)
# views.py
# 10. 获取值
def get_session(request):
# 10.1 获取session中的值
print(request.session) # 是一个对象
print(request.session.get('studio1'))
print(request.session.get('studio2'))
print(request.session.get('studio3'))
# 10.2 返回值
return HttpResponse('哈哈哈')
0. 浏览器中访问 127.0.0.1:8000/set_session
1. 浏览器中访问 127.0.0.1:8000/get_session
get_session的执行结果:
<django.contrib.sessions.backends.db.SessionStore object at 0x000001CBA27C05C0>
Python
MySQL
Linux
request.session.set_expiry(3) 过期清理的是浏览器的数据,数据库的数据还存在
# views.py
# 9. 设置值
def set_session(request):
# 9.1 把session的值添加到request中
request.session['studio1'] = 'Python'
# 9.2 设置过期时间 3秒
request.session.set_expiry(3)
# 9.3 返回值
return HttpResponse('set_session执行了')
# views.py
# 10. 获取值
def get_session(request):
# 10.1 获取session中的值
print(request.session.get('studio1'))
# 10.2 返回值
return HttpResponse('get_session执行了')
0. 浏览器中访问 127.0.0.1:8000/set_session
1. 浏览器中访问 127.0.0.1:8000/get_session
get_session的执行结果:
None
一条session数据可以存多个数据, 后面设置不会覆盖之前的设置.
# views.py # 9. 设置值 def set_session(request): # 9.1 把session的值添加到request中 request.session['studio1'] = 'Python' # request.session['studio2'] = 'MySQL' # 9.2 设置过期时间 3秒 # request.session.set_expiry(3) # 9.3 返回值 return HttpResponse('set_session执行了') # 10. 获取值 def get_session(request): # 10.1 获取session中的值 print(request.session.get('studio1')) print(request.session.get('studio2')) # 10.2 返回值 return HttpResponse('get_session执行了')
request.session.flush() 清理的是浏览器与数据库的数据.
# views.py
# 11. 清除值
def del_session(request):
# 11.1 清除session数据
request.session.flush()
return HttpResponse('已经清除缓存')
生成一个缓存
执行清除
# urls.py
# 10. 登入2
url(r'^login2/', views.login2),
# 11. 主页2
url(r'^home2/', views.home2)
# views.py # 12. 登入2 def login2(request): # 12.1 生成对象 forms_obj = MyForms() if request.POST == 'POST': # 12.2 获取POST中的数据 username = request.POST.get('username') password = request.POST.get('password') # 12.3 返回forms对象 forms_obj = MyForms(request.POST) # 12.4 检验 if username == 'kid' and password == '123': # 12.5 设置session值 request.session['username'] = 'kid666' # 12.6 返回页面 return redirect('/home2/') return render(request, 'login.html', locals()) # 13. 主页2 def home2(request): if request.session.get('username') == 'kid666': return HttpResponse('home2主页') else: return HttpResponse('非法访问')
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>登入功能</title> <!--0. 动态获取静态文件名称 --> {% load static %} <!--1. 导入jQuery js 文件--> <script src="{% static 'js/jquery-3.6.0.min.js' %}"></script> <!--2. 导入 bootstrap css 文件--> <link rel="stylesheet" href="{% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}"> <!--3. 导入 bootstrap js 文件--> <script src="{% static 'bootstrap-3.3.7-dist/js/bootstrap.min.js' %}"></script> </head> <body> <div> <!--4. form表单 post请求 前端不验证 --> <form action="" method="post" novalidate> {% for form in forms_obj %} <p>{{ form.label }}:{{ form }} <span style="color: red;">{{ form.errors.0 }}</span></p> {% endfor %} <input type="submit"> </form> </div> </body> </html>
0. 在浏览器中访问 http://127.0.0.1:8000/home2/
1. 在浏览器中访问 http://127.0.0.1:8000/login2/
之后只要session不过去都可以直接访问 home2 主页
登入装饰器
# urls.py
# 12. index4
url(r'^index4/', views.index4)
# views.py # 12. 登入2 def login2(request): # 12.1 生成对象 forms_obj = MyForms() if request.method == 'POST': # 12.2 获取POST中的数据 username = request.POST.get('username') password = request.POST.get('password') # 12.3 返回forms对象 forms_obj = MyForms(request.POST) # 12.4 检验 if username == 'kid' and password == '123': # 12.5 获取根目录地址 target_url = request.GET.get('next') # 12.6 设置session值 request.session['username'] = 'kid666' # 12.7 判断时候获取到地址 if target_url: return redirect(target_url) else: # 12.8 返回页面 return redirect('/home2/') return render(request, 'login.html', locals()) # 13. 主页2 def home2(request): if request.session.get('username') == 'kid666': return HttpResponse('home2主页') else: return HttpResponse('非法访问') # 14. 登入装饰器 def decorator(func): def inner(request, *args, **kwargs): # 14.1 验证信息 if request.session.get('username') == 'kid666': res = func(request, *args, **kwargs) return res else: # 14.2 获取地址 target_url = request.get_full_path() # 14.3 如果有地址就添加到路径后面 if target_url: print(3) return redirect(f'/login2/?next={target_url}') else: return redirect('/login2/') return inner # 15. index4 @decorator def index4(request): return HttpResponse('index4页面')
# CBV添加装饰器
url(r'^mylogin/', views.MyLogin.as_view()),
from django.views import View
from django.utils.decorators import method_decorator
"""
CBV中django不建议直接给类的方法夹装饰器
无论该装神器能否正常工作都不建议直接加
"""
class MyLogin(View): # 放装饰器的名字
@method_decorator(login_auth)
def get(self, request):
return HttpResponse('我是get')
def post(self, request):
return HttpResponse('我是post')
方式二:可以添加多个针对不同的方式加不同的装饰器.
from django.views import View
from django.utils.decorators import method_decorator
# 给多个属性加装饰器
@method_decorator(login_auth, name='set')
@method_decorator(login_auth, name='post')
class MyLogin(View): # 放装饰器的名字
def get(self, request):
return HttpResponse('我是get')
def post(self, request):
return HttpResponse('我是post')
from django.views import View
from django.utils.decorators import method_decorator
class MyLogin(View):
# 源码中view中的代码,自定义之后就不走父类的,走自己dispath方法
# 看源码中,每个方法需要经过它,就等于所有的方法都加了装饰器
@method_decorator(login_auth)
def dispath(self, request, *args, **kwargs):
pass
def get(self, request):
return HttpResponse('我是get')
def post(self, request):
return HttpResponse('我是post')
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。