一、cookie
写cookie和session之前,先说说http协议 它是:请求-->响应的模式,必须浏览器(客户端)向服务器发出请求之后,服务器才会响应回你了 无状态:就是因为这点才会有cookie这些的由来,无状态就是你的上一次请求,本次请求,下一次请求 都是毫无关联的,就好比你拨打人工服务(发出一个请求),下一次你再拨打人工服务(再一次请求), 她会知道你是谁吗? 无连接:意思就是你发出请求,服务器响应你了,同时会立马关闭此次链接。 现在我们访问某些网站,比如TB网,B站,你在上面登陆了账号,下次再访问的话,还是你自己信息在那里,不是说http协议 是无状态的吗?那我下一次访问服务器就会知道是我在访问网站呢?这就是cookie的作用了。 你在访问一个网站,并且登陆了账号,它的服务器会为你这次请求生成一个cookie并且响应回你,你的浏览器就会保存起来, 下一次再访问该网站的时候,会把这个cookie带上(放在请求头中),这样服务端后台拿到你的cookie,就知道你的身份,并 把你的身份信息也返回到你的网页。这个cookie就相当于你的身份标志了。 一个浏览器可以保存多个cookie?那访问网页的时候,会把所有的cookie都带上?肯定不会这样的,你访问特定的网站,浏览 器内部会帮你处理,带上相应的cookie,不会带上其他网页的cookie。这样也可以降低你的安全风险。 在django中怎么去用呢 对cookie操作,无非就是增加,删除,获取这些,我们在HttpResponse这个对象中操作 那么,我能不能操作 render redirect JsonResponse这些呢? 答案是可以的,上面的最终都是返回的是HttpResponse对象 obj = HttpResponse('ok') obj.set_cookie() #cookie是一个键值对, 源码: set_cookie(self, key, value='', max_age=None, expires=None, path='/', domain=None, secure=False, httponly=False): 上面这个set_cookie的源码,key,value这两个参数不用讲了把,对应的键值对的两个值 max_age ----> 代表过期时间,是None的话,cookie会保持到浏览器关闭,以s最为单位 expires=None ----> 传一个时间对象过去,也是代表过期时间 path='/'----> 代表cookie生效的路径,'/'代表该服务器中的所有路由都能生效,都会携带上 domain=None ----> cookie生效的域名 secure=False ----> 浏览器将通过https来回传cookie httponly=False ----> 只能http协议传输,无法被JavaScript获取 # 其实记得话只需记得过期时间,和前面那两个参数,一个key,一个value obj.set_signed_cookie 源码: def set_signed_cookie(self, key, value, salt='', **kwargs): value = signing.get_cookie_signer(salt=key + salt).sign(value) return self.set_cookie(key, value, **kwargs) # 这是也是添加cookie的方式,它最终还是调了set_cookie方法,在set_cookie基础上又加了些操作 # set_signed_cookie里又这样一个参数salt,相当于加个暗号,让你的cookie更加安全点 # 这个是不是和设置hash值差不多。 删除cookie操作: delete_cookie 你只需要传一个key值就行了 源码: def delete_cookie(self, key, path='/', domain=None): self.set_cookie(key, max_age=0, path=path, domain=domain, expires='Thu, 01-Jan-1970 00:00:00 GMT') 你看,它最终还是执行了set_cookie,只不过它把max_age设置为0 获取到cookie值: 你请求的所携带的数据都在request对象中,所以这个cookie也不例外 方式一:cookie1 = request.COOKIES 方式二:cookie2 =request.META.get('HTTP_COOKIE') cookie1它的返回值是一个字典 {'sessionid': 'j17hk7jxd4excy1efmisirfv4bbjpcdu'} cookie2它就是一个字符串了, request.COOKIES其本质就是通过cookie2的值进行字符串操作,得到的字典 sessionid=j17hk7jxd4excy1efmisirfv4bbjpcdu # 用的话直接用request.COOKIES获取cookie值就行 总结下cookie:1、它是保存在浏览器中的键值对 2、查看cookie,通过request.COOKIES,它是一个字典,取值就是字典取值了 3、set_cookie()和set_signed_cookie(),记住它是HttpResponse的方法
二、session
上面的讲的cookie很好的解决了保持会话的效果,但是毕竟还是有限,它保存在浏览器上对吧,那么用户就可以看到, 其他人也有机会切取到账号密码,所以对用户来说存在一定的安全隐患的,所以必须要有新的保持会话的方式,所以 session这种方式,很好的解决了这个问题,将数据保存在服务端上,外人不容易窃取到,况且还是加密保存的 在django怎么去设置session呢? request.session['name'] = 'zhuyu' # 这一行代码进行了下面几个操作: 1、首先生成了一个随机的字符串,这个字符串代表这这个浏览器的id 2、然后设置一个给这个浏览器设置一个cookie key为sessionid, value就是{'name':'zhuyu'}这个字典所通过加密得到的字符串, 相当于执行HttpResponse.set_cookie('sessionid',字典加密后的字符串) 3、然后保存到数据库中,这个表名为django_session 这样一个浏览器就有了一个唯一的id,作为cookie的value值 那我在上面那行代码继续执行一行代码 request.session['age'] = '21' 那django会进行怎么的操作呢?是继续执行下面那三个操作? 分析下:1、这是不是同一个浏览器发过去的数据,那么这个随机字符串上面是不是已经生成了 2、基于1的想法,所以这个cookie是不是没有发生变化,现在主要是考虑这个字典加密后的字符串了 3、你觉得是生成一个新的加密字符串覆盖直接旧的?还是{'name':'zhuyu','age':'21'}生成 一个随机字符串再覆盖掉之前的? 4、如果是基于3的想法一,生成一个字典加密的字符串覆盖掉之前的?那么你的session永远就是一个值? 你觉得这样好吗?后面我们可以要通过这个加密后的字符串,反解密得到字典,再从数据库中,拿到 该用户的信息,再返回到前台页面,那如果你的判断调节就一个name,就一个age,是根本不能确定 是哪个用户的 5、那应该就是组成一个大的字典,然后对字典进行加密操作,再保存到数据库中。 额额,上面这个这是我yy的,你如果知道的话,可以再下面留言,不过应该每人看的,还是让我一个人在这里yy吧,哈哈 request.session 这是一个对象,不是字典,他重写了__getitem__,__setitem__这两个方法 你可以把他当作一个字典去使用,get取值都行 {'name':'zhuyu','age':'21'} request.session 相当于就是个字典,那么字典的一些方法,你可以使用 取值的话:request.session['name'] request.session.get('name') 设置session数据: request.session['sex'] = '男' request.session.setdefault('name','朱宇') # 意思是假如有name这个key,那就不赋值,没有的话添加{'name':'朱宇'} 删除其中的一个key值:del request.session['sex'] 你可以去试试pop行不行 返回值是列表: request.session.keys() request.session.values() request.session.items() 迭代器,每次返回一个数据: request.session.iteritems() request.session.iterkeys() request.session.itervalues() cookie_value = request.COOKIES.get('sessionid') request.session.exists(cookie_value) # 判断sessionid对应的值,在不在django_session表的session_key中, # 假如浏览器的cookie中没有sessionid,所以cookie_value为None, # 判断就为false。 # 两种删除session的方式 方式一: request.session.delete() #这是删除整个session,删除的是那条记录 #但是浏览器的cookie是不会删掉的 那你下次浏览再带这个cookie请求, request.session.exists(cookie_value)的值就为false了,因为数据库中查询不到 方式二: request.session.flush() # 删除数据库中的session,也删除了浏览器的cookie # 你想想它是怎么实现的? # 不就是执行request.session.delete(),再执行delete_cookie,就是这样吧
三、在django的setting中配置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,默认修改之后才保存(默认)
四、基于FBV和CBV加上session装饰器
之前写过了,我就粘贴了 基于FBV: def login_auth(func): def inner(request, *args, **kwargs): url = request.get_full_path() cook = request.COOKIES.get('sessionid') if request.session.exists(cook): return func(request, *args, **kwargs) else: return redirect('/login/?next_url=%s' % url) return inner # 假如你没有登陆的话,访问订单页面肯定是访问不了,所以让你先去登陆,登陆成功自动跳转到订单页面 def login(request): print(request.session.set_expiry) if request.method == 'GET': return render(request, 'login.html') if request.method == 'POST': import json dic = json.loads(str(request.body, encoding='utf-8')) name = dic.get('name') pwd = dic.get('pwd') user = models.User.objects.filter(name=name, pwd=pwd) if user: request.session['name'] = name request.session['pwd'] = pwd path = request.GET.get('next_url') if path: url = path else: url = '/index/' new_dic = {'status': '100', 'info': url} else: new_dic = {'status': '200', 'info': '用户名或密码错误'} return JsonResponse(new_dic) @login_auth def order(request): return render(request, 'order.html') 基于CBV: class Buy_cart(views.View): def get(self, request): return HttpResponse('get') def post(self, request): return HttpResponse('post') @method_decorator(login_auth) def dispatch(self, request, *args, **kwargs): return super().dispatch(request, *args, **kwargs) # 装饰器在上面
## 今天就到这里!!
## 提醒下,你要练习cookie,session的话,记得清理下浏览器的cookie,好了,没事了