COOKIE&SESSION
知识储备
由于http协议无法保持状态,但实际情况,我们却又需要“保持状态”,因此cookie就是在这样一个场景下诞生。
cookie的工作原理是:由服务器产生内容,浏览器收到请求后保存在本地;当浏览器再次访问时,浏览器会自动带上cookie,这样服务器就能通过cookie的内容来判断这个是“谁”了。
cookie虽然在一定程度上解决了“保持状态”的需求,但是由于cookie本身最大支持4096字节,以及cookie本身保存在客户端,可能被拦截或窃取,因此就需要有一种新的东西,它能支持更多的字节,并且他保存在服务器,有较高的安全性。这就是session。
问题来了,基于http协议的无状态特征,服务器根本就不知道访问者是“谁”。那么上述的cookie就起到桥接的作用。
我们可以给每个客户端的cookie分配一个唯一的id,这样用户在访问时,通过cookie,服务器就知道来的人是“谁”。然后我们再根据不同的cookie的id,在服务器上保存一段时间的私密资料,如“账号密码”等等。
总结而言:cookie弥补了http无状态的不足,让服务器知道来的人是“谁”;但是cookie以文本的形式保存在本地,自身安全性较差;所以我们就通过cookie识别不同的用户,对应的在session里保存私密的信息以及超过4096字节的文本
Django实现COOKIE
设置cookie
obj = HttpResponse(...) 或 obj= render(request, ...) 或 obj= redirect()
obj.set_cookie(key,value,...)
obj.set_signed_cookie(key,value,salt=
‘加密盐‘
,...)
获取cookie
request.COOKIES.get(‘key‘)
request.get_signed_cookie(key, default=
RAISE_ERROR, salt
=
‘‘, max_age
=
None
)
删除cookie
response.delete_cookie("cookie_key",path="/",domain=name)
参数
key, 键 value=‘‘, 值 max_age=None, 超长时间 expires=None, 超长时间 path=‘/‘, Cookie生效的路径,浏览器只会把cookie回传给带有该路径的页面,这样可以避免将cookie传给站点中的其他的应用。/ 表示根路径,特殊的:根路径的cookie可以被任何url的页面访问 domain=None, Cookie生效的域名你可用这个参数来构造一个跨站cookie。如, domain=".example.com"所构造的cookie对下面这些站点都是可读www.example.com 、 www2.example.com 和an.other.sub.domain.example.com 。 如果该参数设置为 None ,cookie只能由设置它的站点读取。 secure=False, 如果设置为 True ,浏览器将通过HTTPS来回传cookie。 httponly=False 只能http协议传输,无法被javascript获取 (不是绝对,底层抓包可以获取到也可以被覆盖
$.cookie("key", value,{ path: ‘/‘ })
Django实现SESSION
设置Session
request.session[‘key‘]=‘value‘ ‘‘‘ 实际进行的操作: 1. 检查请求是否有sessionid,且是否存在与数据库,存在则对session_data进行更新 2. 若不等,则创建随机字符串 3. set_cookie(‘sessionid‘,‘随机字符串‘) 4. 在session表中添加记录 session-key session-data 随机字符串 {"key":"value"}-------------进行处理后的 ‘‘‘
获取Session
session_name=request.session[‘key‘] ‘‘‘ 实际进行了哪些操作: 1. 取随机字符串request.COOKIE.get(‘sessionid‘) 2. 在session表中进行过滤: obj=django-session.objects.filter(session-key=random_str).first() obj.session-data.get("user") ‘‘‘
其他
#删除Sessions值 del request.session["session_name"] #检测是否操作session值 if "session_name" is request.session:
配置
Django默认支持Session,并且默认是将Session数据存储在数据库中,即:django_session 表中。 a. 配置 settings.py SESSION_ENGINE = ‘django.contrib.sessions.backends.db‘ # 引擎(默认) 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,默认修改之后才保存(默认
a. 配置 settings.py SESSION_ENGINE = ‘django.contrib.sessions.backends.cache‘ # 引擎 SESSION_CACHE_ALIAS = ‘default‘ # 使用的缓存别名(默认内存缓存,也可以是memcache),此处别名依赖缓存的设置 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,默认修改之后才保存
a. 配置 settings.py SESSION_ENGINE = ‘django.contrib.sessions.backends.file‘ # 引擎 SESSION_FILE_PATH = None # 缓存文件路径,如果为None,则使用tempfile模块获取一个临时地址tempfile.gettempdir() 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,默认修改之后才保存
def login_session(request): if request.method==‘POST‘: user=request.POST.get(‘user‘) pwd=request.POST.get(‘pwd‘) ret=UserInfo.objects.filter(name=user,pwd=pwd) if ret: request.session[‘user‘]=user return redirect(‘/index_session/‘) return render(request,‘login.html‘) def index_session(request): user=request.session.get(‘user‘) if not user: return redirect(‘/login_session/‘) return render(request,‘index.html‘,locals())
Django的用户认证
auth
利用auth模块中的一些方法来进行认证 from django.contrib import auth
authenticate()
提供了用户认证,即验证用户名以及密码是否正确,一般需要username password两个关键字参数
如果认证信息有效,会返回一个 User 对象。authenticate()会在User 对象上设置一个属性标识那种认证后端认证了该用户,且该信息在后面的登录过程中是需要的。当我们试图登陆一个从数据库中直接取出来不经过authenticate()的User对象会报错的
user = authenticate(username=‘someone‘,password=‘somepassword‘)
login(HttpRequest, user)
该函数接受一个HttpRequest对象,以及一个认证了的User对象
此函数使用django的session框架给某个已认证的用户附加上session id等信息。
login(request, user)
logout(request)
该函数接受一个HttpRequest对象,无返回值。当调用该函数时,当前请求的session信息会全部清除。该用户即使没有登录,使用该函数也不会报错。
logout(request)
User对象
User 对象属性:
username, password(必填项)password用哈希算法保存到数据库
is_staff : 用户是否拥有网站的管理权限.
is_active : 是否允许用户登录, 设置为``False``,可以不用删除用户来禁止 用户登录
is_authenticated()
如果是真正的 User 对象,返回值恒为 True 。 用于检查用户是否已经通过了认证。
通过认证并不意味着用户拥有任何权限,甚至也不检查该用户是否处于激活状态,这只是表明用户成功的通过了认证。 这个方法很重要, 在后台用request.user.is_authenticated()判断用户是否已经登录,如果true则可以向前台展示request.user.name
if not request.user.is_authenticated(): return redirect(‘%s?next=%s‘ % (settings.LOGIN_URL, request.path))
django自带用于此种情况的装饰器:login_requierd()
from django.contrib.auth.decorators import login_required @login_required def my_view(request):
若用户没有登录,则会跳转到django默认的 登录URL ‘/accounts/login/ ‘ (这个值可以在settings文件中通过LOGIN_URL进行修改)。并传递 当前访问url的绝对路径 (登陆成功后,会重定向到该路径)。
创建用户
from django.contrib.auth.models import User user = User.objects.create_user(username=‘‘,password=‘‘,email=‘‘)
修改密码set_password()
user = User.objects.get(username=‘‘) user.set_password(password=‘‘) user.save
check_password(passwd)
用户需要修改密码的时候 首先要让他输入原来的密码 ,如果给定的字符串通过了密码检查,返回 True
基于auth认证实现登录:
def login(request): ‘‘‘ 登录验证 :param request: :return: ‘‘‘ if request.method==‘POST‘: username=request.POST.get(‘username‘) pwd=request.POST.get(‘pwd‘) input_valid_code=request.POST.get(‘valid_code‘) valid_code=request.session.get(‘valid_code‘) login_response={‘user‘:None,‘error_msg‘:‘‘} #进行验证码的比较 if valid_code.upper()==input_valid_code.upper(): user=auth.authenticate(username=username,password=pwd) if user: auth.login(request,user) login_response[‘user‘]=user.username else: login_response[‘error_msg‘]=‘用户名或密码错误!‘ else: login_response[‘error_msg‘]=‘验证码错误!‘ import json return HttpResponse(json.dumps(login_response)) return render(request,‘login.html‘,locals())