session是一种机制,是识别用户身份的机制,服务端给客户端一个session ID, 此后这个session ID就唯一的代表这个用户。现在有两个问题需要考虑:
通常来说,当你登录一个web服务时,它就会给你发放一个session ID,在你登录后,你做的操作都是对你这个用户生效的,如果你没有登录,这些操作是不被允许的,因此后端要根据session ID来判断是你否已经登录。此外,服务端也会在session里存储你的一些关键数据,比如你的用户id,姓名,等等,这些信息虽然可以从数据库里查询,但是保存在session里相比于保存在数据库里更容易获取。
记下来看第二个问题,服务端告知客户端session ID,是通过cookie进行的,同样,客户端的请求里也会通过cookie把session ID发送给服务端。
关于session,网上讨论的文章非常多,但很长时间里,我都搞不懂它是个什么东西,因为太多的文章都在人云亦云,反复抄来抄去,以至于大家讲的东西都很接近但又重来不给具体实例,咱们这篇文章就要打破这个不好的习惯。
很长一段时间里,我对session的理解都非常模糊,模糊主要体现在以下两点:
先看第一个问题,session ID怎样生成,生成是一个动词,做这个动作的主体是谁呢?是服务端,如果你的服务是java的,用tomcat部署,那么session ID shi tomcat生成的,如果你的服务是flask编写的,那么session ID是flask框架生成的,在response里,通过Set-Cookie 首部传给前端,虽然我们叫它session ID,但在cookie里,它的key却并没有明确的规范,因此你能看到SESSION,也能看到SESSIONID,tomcat生成的叫JSESSIONID。
使用session的目的是为了保存用户相关的少量重要信息,避免频繁的查询数据库,那么session的数据保存在哪里呢?有4中保存方法
保存在内存中是一个可行的方案,但如果服务挂掉了,所有用户的session也就丢失了。
保存在本地文件比内存安全一些,但对于多个节点的web服务会遇到session共享问题,你在A服务器上保存了小明的session数据,但是小明下一次的请求来到了B服务器上,而B服务器上没有小明的session信息,这种情况可以根据用户的IP将请求路由到固定的服务节点上解决。
保存到数据库,即安全,又能实现session共享。保存到cookie里,也是一个可行的方案,flask框架就是这样做的。
我们使用flask 做一个简单的web,设计一个登录接口,用户只有登录以后才能访问其他页面,我在session里保存用户的username,如果session里没有username则不允许用户访问其他页面。
from flask import Flask, session
app = Flask(__name__)
app.config['SECRET_KEY'] = 'hard to gusss'
@app.route('/login/<string:username>')
def name_view(username):
session['username'] = username
return 'ok'
@app.route('/')
def get_name():
if 'username' not in session:
return 'not login'
else:
return 'welcome ' + session['username']
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5500)
使用flask的session时,需要设置SECRET_KEY,flask的session数据保存在cookie里,而cookie是明文的,因此需要对session数据进行加密,SECRET_KEY就是用来加密的,如果泄露了,你的session就不安全了。
服务启动,如果你直接访问http://127.0.0.1:5500/, 得到的是not login,这说明你还没有登录。想要登录,需要访问login接口,比如下面的地址
http://127.0.0.1:5500/login/sheng
真正的登录应该使用post请求,本例子为了方便,使用get请求来模拟登录,用户名是sheng,后端也没有加什么处理逻辑,认为登录是成功的,将username设置到session里,这时你可以通过浏览器的开发者工具来观察后端的响应,会有一个 Set-Cookie
Set-Cookie: session=eyJ1c2VybmFtZSI6InNoZW5nIn0.YWaAyg.EWTHe6YexZ6SYClFztPj1aK1PBs; HttpOnly; Path=/
在flask框架里,session ID在cookie里用session做key来保存,前面已经讲过,具体的名称是没有规范的。flask框架的特别之处在于,session ID还承担了保存数据的功能,这便是说,eyJ1c2VybmFtZSI6InNoZW5nIn0.YWaAyg.EWTHe6YexZ6SYClFztPj1aK1PBs里隐藏着username=sheng这条信息,只是它被加密了,你看不出来。
好了,已经登录成功,接下来,再次访问http://127.0.0.1:5500/, 你得到了welcome sheng, username=sheng这条信息又被客户端通过cookie传回给了服务端。
对于session,可以有以下几个操作
这几种操作都比较简单,我提供示例代码
session['username'] = 'sheng' # 设置sesion
username = session['username'] # 获取值,如果不存在,会报错
username = session.get('username') # 获取值,不存在返回None,不会报错,类似字典的get
session.pop('username') # 删除session
session.clear # 清空所有session
下面的示例,我设置session的过期时间是1分钟
from flask import Flask, session
from datetime import timedelta
app = Flask(__name__)
app.config['SECRET_KEY'] = 'hard to gusss'
app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(seconds=60)
@app.route('/login/<string:username>')
def name_view(username):
session['username'] = username
# session.permanent = True
return 'ok'
@app.route('/')
def get_name():
if session.get('username') is None:
return 'not login'
else:
return 'welcome ' + session['username']
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5500)
如果通过配置PERMANENT_SESSION_LIFETIME设置session过期时间,session.permanent = True可以不执行,设置permanent为True的目的是让浏览器记住过期时间,如果不设置,你在浏览器里查不到session的过期时间,但过期时间依然是生效的。
QQ交流群: 211426309