djang -- cookie和session
一.cookie -- 小甜点
1.由来
http协议,两个特点: 无状态、无连接(http//1.1版本后短连接)
无状态: -- http协议不会记录客户端和服务端的任何状态信息,每次请求都是独立的,导致不能维持会话
状态可以理解为客户端和服务器在某次会话中产生的数据,那无状态的就以为这些数据不会被保留。会话中产生的数据又是我们需要保存的,也就是说要“保持状态”。因此Cookie就是在这样一个场景下诞生。
访问哪一个网址,都要验证用户的身份,但是还有保证什么呢,用户登陆过之后,还要保证登陆了的用户不需要再重复登陆,就能够访问我网站的其他的网址的页面,对不对,但是http无状态啊,怎么保证这个事情呢?此时就要找cookie了。
2.什么是cookie
cookie是浏览器的技术,Cookie具体指的是一段小信息,它是服务器发送出来存储在浏览器上的一组组键值对,可以理解为服务端给客户端的一个小甜点,下次访问服务器时浏览器会自动携带这些键值对,以便服务器提取有用信息。
3.cookie原理
cookie的工作原理是:浏览器第一次访问服务端,带着一个空的cookie,然后由服务器产生内容,浏览器收到相应后保存在本地;当浏览器再次访问时,浏览器会自动带上Cookie,这样服务器就能通过Cookie的内容来判断这个是“谁”了。
4.基于cookie的登陆认证
路由:urls.py
from app01 import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^login/', views.login, name='login'),
url(r'^home/', views.home,name='home'),
url(r'^person/', views.person,name='person'),
]
视图:views.py -- 写cookie登陆认证
from django.shortcuts import render,redirect
def login(request):
if request.method == 'GET':
return render(request,'login.html')
else:
uname = request.POST.get('username')
pwd = request.POST.get('password')
if uname == 'jia' and pwd == '123': # 用户名密码输入正确才添加cookie
ret = redirect('home')
# ret.set_cookie('is_login',True) #设置cookie键值对
ret.set_cookie('is_login',True,5) #设置cookie数据5秒后清除
ret.set_cookie('uname', uname) #可以设置多个值
return ret
# 浏览器响应头中有Set-Cookie: is_login=True;显示cookie数据
else:
return redirect('login')
def home(request): # 我们要求:没有登陆,不能直接访问home页面
print(request.COOKIES)
# 可以拿到本次访问携带的cookie字典数据
# {'is_login': 'True', 'uname': 'jia'}
# 网络传输 -- bytes类型数据(编码处理) -- 所以值都是字符串了
# 基于cookie的登录认证(判断用户是否处于登录状态)
is_login = request.COOKIES.get('is_login')
# cookie中有登录成功之后的标识信息才能正常访问home页面
# 不然就让它去login页面登录
if is_login == 'True':
return render(request,'home.html')
else:
return redirect('login')
templates目录下HTML文件:
login.html
<body>
<form action="" method="post">
用户名: <input type="text" name="username">
密码: <input type="password" name="password">
<input type="submit">
</form>
</body>
home.html
<body>
<h1>这是首页</h1>
<a href="{% url 'person' %}">个人中心</a>
</body>
5.cookie登录认证装饰器
视图:views.py ,其他同上
from django.shortcuts import render,redirect,HttpResponse
# 基于cookie的登录认证装饰器
def outer(func):
def inner(request,*args,**kwargs):
is_login = request.COOKIES.get('is_login')
if is_login == 'True':
res = func(request,*args,**kwargs)
return res
else:
return redirect('login')
return inner
@outer # 访问其他页面时登陆认证加装饰器
def person(request):
return render(request,'person.html')
@outer
def home(request):
return render(request, 'home.html')
def login(request):
if request.method == 'GET':
return render(request,'login.html')
else:
uname = request.POST.get('username')
pwd = request.POST.get('password')
if uname == 'jia' and pwd == '123': # 用户名密码输入正确才添加cookie
ret = redirect('home')
# ret.set_cookie('is_login',True) #设置cookie键值对
ret.set_cookie('is_login',True,5) #设置cookie数据5秒后清除
ret.set_cookie('uname', uname) #可以设置多个值
return ret
# 浏览器响应头中有Set-Cookie: is_login=True;显示cookie数据
else:
return redirect('login')
6.django中操作cookie
设置cookie
rep = HttpResponse(...)
rep = render(request, ...)
rep.set_cookie(key,value,...) #包含添加和修改,键和值
# 设置签名cookie --
# rep.set_signed_cookie(key,value,salt='加密盐', max_age=None, ...)
获取cookie
request.COOKIES.get('is_login')
request.COOKIES['key']
# 获取签名cookie
# request.get_signed_cookie(key, default=RAISE_ERROR, salt='', max_age=None)
删除cookie
def logout(request):
rep = redirect("/login/")
rep.delete_cookie("user") # 删除用户浏览器上之前设置的usercookie值
return rep
7.Set_cookie方法
class HttpResponseBase:
def set_cookie(self,
key, 键
value='', 值
max_age=None, 有效时间,max_age=20意思是这个cookie20秒后就消失了,默认时长是2周,这个是以秒为单位的,cookie需要延续的时间(以秒为单位),如果参数是 None`` ,这个cookie会延续到浏览器关闭为止。
expires=None, 有效时间,值是一个datetime类型的时间日期对象,到这个日期就失效的意思,用的不多,expires默认None ,cookie失效的实际日期/时间。
path='/', 指定Cookie生效的路径,就是访问哪个路径可以得到cookie,'/'是所有路径都能获得cookie,浏览器只会把cookie回传给带有该路径的页面,这样可以避免将cookie传给站点中的其他的应用。 / 表示根路径,特殊的:根路径的cookie可以被任何url的页面访问
domain=None, Cookie生效的域名,你可用这个参数来构造一个跨站cookie。
如, domain=".example.com",所构造的cookie对下面这些站点都是可读的:
www.example.com 、 www2.example.com
如果该参数设置为 None ,cookie只能由设置它的站点读取。
secure=False, 如果设置为 True ,浏览器将通过HTTPS来回传cookie。HTTP不生效
httponly=False 如果为True,只能http协议传输,无法被JavaScript获取(不是绝对,底层抓包可以获取到也可以被覆盖)
): pass
8.cookie设置中文时的编码问题:(了解)
- 所以尽量不要出现中文
cookie在设置时不允许出现中文。非要设置中文的怎么办,看下面的解决方案:
# 方式1
def login(request):
ret = HttpResponse('ok')
ret.set_cookie('k1','你好'.encode('utf-8').decode('iso-8859-1'))
#取值:request.COOKIES['k1'].encode('utf-8').decode('iso-8859-1').encode('iso-8859-1').decode('utf-8')
return ret
方式2 json
def login(request):
ret = HttpResponse('ok')
import json
ret.set_cookie('k1',json.dumps('你好'))
#取值 json.loads(request.COOKIES['k1'])
return ret
9.Cookie规范
- Cookie大小上限为4KB;
- 一个服务器最多在客户端浏览器上保存20个Cookie;
- 一个浏览器最多保存300个Cookie,因为一个浏览器可以访问多个服务器。
上面的数据只是HTTP的Cookie规范,但在浏览器大战的今天,一些浏览器为了打败对手,为了展现自己的能力起见,可能对Cookie规范“扩展”了一些,例如每个Cookie的大小为8KB,最多可保存500个Cookie等!但也不会出现把你硬盘占满的可能!
注意,不同浏览器之间是不共享Cookie的。也就是说在你使用IE访问服务器时,服务器会把Cookie发给IE,然后由IE保存起来,当你在使用FireFox访问服务器时,不可能把IE保存的Cookie发送给服务器。
10.cookie的缺点:
1 存储数据的大小有上限
2 明文存储数据 (不安全,敏感数据尽量不要通过cookie存储)
为了解决cookie的弊端,session技术出现了
二.session
1.简介:
Session是服务器端技术,Django的session技术是基于cookie实现的,利用这个技术,服务器在运行时可以 为每一个用户的浏览器创建一个其独享的session对象,
cookie缺点:
1 存储数据的大小有上限
2 明文存储数据 (数据储存在客户端浏览器,不安全,敏感数据尽量不要通过cookie存储)
session优点:
1.数据存在服务端,比较安全,存储大小无上限
2.传输效率也高,cookie中只有一对随机字符串
问题来了,基于HTTP协议的无状态特征,服务器根本就不知道访问者是“谁”。那么上述的Cookie就起到桥接的作用。
我们可以给每个客户端的Cookie分配一个唯一的id,这样用户在访问时,通过Cookie,服务器就知道来的人是“谁”。然后我们再根据不同的Cookie的id,在服务器上保存一段时间的私密资料,如“账号密码”等等。
总结而言:Cookie弥补了HTTP无状态的不足,让服务器知道来的人是“谁”;但是Cookie以文本的形式保存在本地,自身安全性较差;所以我们就通过Cookie识别不同的用户,对应的在Session里保存私密的信息以及超过4096字节的文本。
另外,上述所说的Cookie和Session其实是共通性的东西,不限于语言和框架。
2.django操作session
基于session的登录认证
视图:views.py -- 其他页面与cookie一样
from django.shortcuts import render,redirect,HttpResponse
# 基于session的登录认证装饰器
def outer(func):
def inner(request,*args,**kwargs):
is_login = request.session.get('is_login')
if is_login:
res = func(request,*args,**kwargs)
return res
else:
return redirect('login')
return inner
def login(request):
if request.method == 'GET':
return render(request,'login.html')
else:
uname = request.POST.get('username')
pwd = request.POST.get('password')
if uname == 'jia' and pwd == '123':
ret = redirect('home')
# 以键值方式设置session
request.session['is_login'] = True
request.session['uname'] = uname
'''
1 生成随机字符串asdf,放到cookie中(sessionid:asdf)
2 在数据库表(django-session,先进行数据库同步指令)中,
数据表中有三个字段:
data = 字段序列化然后加密is_login和uname数据
session_key --> asdf 随机字符串
session_data --> data 加密数据
session_expire --> 默认两周 有效时间
'''
return ret
else:
return redirect('login')
@outer #加session登陆认证装饰器
def person(request):
return render(request, 'person.html')
def home(request):
# 获取session
is_login = request.session.get('is_login')
'''
1 取出本次cookie中的sessionid对应的值asdf随机字符串
2 拿着asdf随机字符串去django-session表中获取保存的那条记录
3 将该记录中的session_data进行解密并反序列化,然后取出is_login键对应的值
'''
print(is_login, type(is_login)) # True <class 'bool'>
if is_login:
return render(request, 'home.html')
else:
return redirect('login')
session的基本操作
# 1.取值
request.session['k1']
request.session.get('k1',None) #request.session这句是帮你从cookie里面将sessionid的值取出来,将django-session表里面的对应sessionid的值的那条记录中的session-data字段的数据给你拿出来(并解密),get方法就取出k1这个键对应的值
# 2.设置值
request.session['k1'] = 123
request.session.setdefault('k1',123) # 存在则不设置
# 3.删除值,删除某个键值对
del request.session['k1'] #django-session表里面同步删除
# 4.所有 键、值、键值对
request.session.keys()
request.session.values()
request.session.items()
# 5.会话session的key
session_key = request.session.session_key 获取sessionid的值
# 6.将所有Session失效日期小于当前日期的数据删除,将过期的删除
request.session.clear_expired()
# 7.检查会话session的key在数据库中是否存在
request.session.exists("session_key") #session_key就是那个sessionid的值
# 8.删除当前会话的所有Session数据
request.session.delete()
# 9.删除当前的会话数据并删除会话的Cookie。
request.session.flush() # 删除cookie中的sessionid值,并且同步删除数据库的记录
# 10.设置会话Session和Cookie的有效期设置
request.session.set_expiry(value)
* 如果value是个整数,session会在些秒数后失效。
* 如果value是个datatime或timedelta,session就会在这个时间后失效。
* 如果value是0,用户关闭浏览器session就会失效。
* 如果value是None,session会依赖全局session失效策略。
一个服务端对应一个浏览器(一个页面只能登陆一个用户),只有一个sessionid
Django中的session配置
1. 数据库Session
SESSION_ENGINE = 'django.contrib.sessions.backends.db' # 引擎(默认)
2. 缓存Session
SESSION_ENGINE = 'django.contrib.sessions.backends.cache' # 引擎
SESSION_CACHE_ALIAS = 'default' # 使用的缓存别名(默认内存缓存,也可以是memcache),此处别名依赖缓存的设置
3. 文件Session
SESSION_ENGINE = 'django.contrib.sessions.backends.file' # 引擎
SESSION_FILE_PATH = None # 缓存文件路径,如果为None,则使用tempfile模块获取一个临时地址tempfile.gettempdir()
4. 缓存+数据库
SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db' # 引擎
5. 加密Cookie Session
SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies' # 引擎
其他公用设置项:
SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串(默认)
SESSION_COOKIE_PATH = "/" # Session的cookie保存的路径(默认)
SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名(默认)
SESSION_COOKIE_SECURE = False # 是否Https传输cookie(默认)
SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http传输(默认)
SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周)(默认)
SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否关闭浏览器使得Session过期(默认)
SESSION_SAVE_EVERY_REQUEST = False # 是否每次请求都保存Session,默认修改之后才保存(默认)