我们现在来说一个例子。当你要访问某个网站时,发现无法访问,并且它可能会直接跳转到登录页面让你先登录。OK,那就先登录,登录之后,就可以访问该网站的任意链接。但是http不是无连接的吗,每次请求一个网页都是一次全新的请求,那么服务器为什么就能知道你是谁了呢?肯定是你身上有某个标记,并且它能看懂这个标记对吧。
这就涉及到cookie和session。
一.Cookie
在你登录或者注册之后,服务器就会在你身上做一个特别的标记,这个标记就是cookie。而且很多网站之间的cookie是独立的。比如你可以测试一下,在你访问了CSDN之后,你可以在当前页面按F12,找到对应的cookie。然后你又去另一个已登录的网站下,再按F12找到cookie,你会发现cookie是不一样的。并且在CSDN下的cookie不会出现在你后来去访问的那个网站下,所以说很多网站的cookie都是独立的。
比如我在CSDN下可以查看到如下信息,有我的用户名,当然这只是一部分而已。
这样,我们之后再去访问该网站的其他链接时,就可以直接跳转到所请求的页面了,因为在我们身上有该网站所做的标记。当你注销的时候,就会将该网站的这些标记删除,这样下一次你访问该网站时,又会被要求先登录。
技术实现(服务器如何在本地的电脑上做标记呢):
1. 服务器设置cookie:
比如你登录成功之后,一般会跳转到主页,那么后端代码可以这样写:
response = redirect('/') # 重定向到主页
response.set_cookie('username', 'Your username', max_age=60) # 设置cookie,{"username": "Your username"}
注意:cookie其实是一些键值对,也就是字典,如上的例子中,username就是键,后面紧跟的就是这个键的值。max_age是一个可选参数,表示该cookie存在的时间,除非用户自己将cookie中的信息删除或者注销,默认是一直存在。max_age=60表示存在60秒,时间一到,这个cookie就会自动删除,那么相当于用户就要被迫下线。
这儿也可以设置多个cookie,保持键不一样就行了,如果一样,那就会覆盖之前设置cookie。
2. 删除cookie
当用户注销时,服务器应该将客户端的cookie删除,删除的命令是
response = redirect('/login/') # 重定向到登录页面
response.delete_cookie('username', path='/') # 只删除{"username": "Your username"}
del request.COOKIES["username"] # 只删除{"username": "Your username"}
response.flush() # 删除所有的cookie
但是我们会发现,这所有的标记都是在客户端,而且客户端自己的cookie是可以被查看的,并且也是可以修改的。那么,如果你的cookie被不怀好意的人获取,他不就可以在他自己的电脑上手动的添加这些cookie,然后就可以顺利的访问你的该账号的网站了,因为身上已经有这些标记的,所以根本都不需要登录。所以单纯的用cookie是很不安全的。因此有了另外一个东西。session
二. session
根据上面分析的情况,我们要怎么防止别人蓄意伪造cookie来获取网站的内容呢?之前的cookie是保存在客户端的,并且客户端可以查看和修改,那么怎样才能防止这种问题呢?我们是不是可以在服务器上再加一个标记,因为是保存在服务器上,所以别人也就无法修改和查看,那么就无法跳过登录这一步,这样就可以保护用户的账号安全。
不过session也不是单独使用的,它要和cookie一起使用。如果用户的浏览器禁用了cookie,那么session设置了也没有意义。
事实上,django在设置session的时候,就会自动在客户端设置一个cookie,键为sessionid,值就是一个很复杂的字符串。用户访问网站时,就相当于拿着这个sessionid去,服务器就会去找该sessionid对应的字段,如果找到了,就会读取session的信息,用该信息判断用户是否是已经登录的用户。
技术实现
1. 配置session
在settings.py中加入下面这些内容
# 配置Session
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,默认修改之后才保存(默认)
2. 设置session
request.session['is_login'] = True # 设置登录状态为True
request.sesion['username'] = "Your username" # 设置username
这样session中就保存了{"is_login": True, "username": "Your username"}这样的内容了,这些内容默认是在django_session这张表中的。这张表在使用python manage.py makemigrations和python manage.py migrate之后,就会自动创建。打开结构是这样的:
图中的1,2,3是我手动加的,1处也就是session_key对应的就是客户端cookie中sessionid的值,而我们设置的session都保存在session_data,expire_data是session过期时间,默认是两个星期。
所以现在读者应该已经知道session和cookie是如何一起搭配使用的了。就是客户端访问网站时,就会拿着这个cookie中的sessionid去,而该sessionid就是django_session 表中的session_key,所以服务器会将客户端的sessionid去django_session 这张表查找,找到相应的字段后,就读取到了该用户的session的信息。这样就可以判断用户是否是已经登录过了。
3. 删除session
del request.session['is_login'] # 只删除{"is_login": True}
request.session.flush() # 删除所有的sesion
4. 扩展
上面的cookie和session,其实都是键值对,所以其实使用的方法除了上面的flush, del之外,python中字典的方法都是可以用的,比如
clear() # 清除,更flush一样
items() # 获取所有的键值
keys() # 获取所有的键,
values() # 获取所有的值
等。