flask-session
flask-session就是将session中而不再是放到浏览器的cookie中了
要使用flask-session首先需要安装一下
pip3 install flask-session
如果想要将session放到redis中,当然是要配置一下了
from flask import Flask,session from flask_session import RedisSessionInterface app = Flask(__name__) app.secret_key='djksahdk' #默认方式保存session,是将session保存到浏览器的cookie中的 # from flask.sessions import SecureCookieSessionInterface # app.session_interface=SecureCookieSessionInterface() #方式一: redis保存session # from redis import Redis # app.session_interface=RedisSessionInterface( # redis=Redis(host='127.0.0.1',port=6379), #连接redis # key_prefix = "dsjfal" #这个前缀可以随便写,在save_session时,会用前缀+sid这个随机字符串 # ) # 方式二: redis保存到session from flask.ext.session import Session from redis import Redis app.config['SESSION_TYPE'] = 'redis' app.config['SESSION_REDIS'] = Redis(host='127.0.0.1',port='6379') Session(app) @app.route('/login') def login(): session['k1'] = 123 return 'login' @app.route('/index') def index(): v =session['k1'] print(v) return 'index' if __name__ == '__main__': app.run()
flask-session的作用:将默认保存在签名cookie中的值,保存到 redis/memcached/file/mongodb/sqlalchemy中
flask中自带的session其实是通过app.session_interface = SecureCookieSessionInterface()来实现的对session的操作,如果我想使用flask-session,只需要将SecureCookieSessionInterface给换成是RedisSessionInterface就可以了.那么flask_session中都做了什么呢
flask_session中有也有两个函数open_session和save_session,先来看open_session中干了什么.
def open_session(self, app, request): sid = request.cookies.get(app.session_cookie_name) if not sid: sid = self._generate_sid() return self.session_class(sid=sid, permanent=self.permanent) if self.use_signer: signer = self._get_signer(app) if signer is None: return None try: sid_as_bytes = signer.unsign(sid) sid = sid_as_bytes.decode() except BadSignature: sid = self._generate_sid()
#请求第一次来,返回一个特殊的字典: sid = dlasjfas return self.session_class(sid=sid, permanent=self.permanent) if not PY2 and not isinstance(sid, text_type): sid = sid.decode('utf-8', 'strict') val = self.redis.get(self.key_prefix + sid) if val is not None: try: data = self.serializer.loads(val) return self.session_class(data, sid=sid) except: return self.session_class(sid=sid, permanent=self.permanent) return self.session_class(sid=sid, permanent=self.permanent)
sid = request.cookies.get(app.session_cookie_name)是获取浏览器中发过来的session中的value,我们想把session放到redis中,请求第一次过来,session是没有值的,如果第一次访问没有session的值,就会执行
signer = self._get_signer(app),_get_signer(app)就会获取到一个唯一标识,然后返回一个特殊的字典放到Local()中
def _generate_sid(self): return str(uuid4())
视图中对session进行操作,例如设置了session['k1']=v1,视图处理完成,在返回数据给浏览器之前要执行save_session
def save_session(self, app, session, response): domain = self.get_cookie_domain(app) #取当前的域名 path = self.get_cookie_path(app) #取cookie的地址 if not session: if session.modified: self.redis.delete(self.key_prefix + session.sid) response.delete_cookie(app.session_cookie_name, domain=domain, path=path) return httponly = self.get_cookie_httponly(app) secure = self.get_cookie_secure(app) expires = self.get_expiration_time(app, session) #过期时间 val = self.serializer.dumps(dict(session)) #进行序列化 self.redis.setex(name=self.key_prefix + session.sid, value=val, time=total_seconds(app.permanent_session_lifetime)) if self.use_signer: session_id = self._get_signer(app).sign(want_bytes(session.sid)) else: session_id = session.sid response.set_cookie(app.session_cookie_name, session_id, expires=expires, httponly=httponly, domain=domain, path=path, secure=secure)
由于现在session中有值,就不走判断,继续往下执行,val = self.serializer.dumps(dict(session))是对session进行序列化,序列化的方式是pickle,通过pickle把这个字典进行了序列化,此时这个字典是{sid:'xxx','k1':'v1'}
serializer = pickle
将序列化之后的session字符串设为值,前缀(self.key_prefix)和sid为键,把它放到redis中
self.redis.setex(name=self.key_prefix + session.sid, value=val,
time=total_seconds(app.permanent_session_lifetime))
然后将session的唯一标识sid保存到浏览器的session中
response.set_cookie(app.session_cookie_name, session_id, expires=expires, httponly=httponly, domain=domain, path=path, secure=secure)
flask-session中的注意事项:
1.session中存储的是字典,那么修改字典中的元素时,会造成数据不更新
解决方法是: 方法一:在设置过session后,再写上session['modified']=True
方法二:在settings中设置SESSION_REFRESH_EACH_REQUEST= True 并且在用户验证成功之后写上session.permanent=True(redis中默认是True)
小应用:
目录结构:
from datetime import timedelta from redis import Redis class Config(object): DEBUG = True SECRET_KEY = "dsjlajfla" PERMANENT_SESSION_LIFETIME = timedelta(minutes=20) #设置session超时时间是20分钟,20分钟之后就失效了 # 如果写上下面这一句还需要在用户登录成功之后写上session.permanent=True,才能对session的二级数据进行修改 SESSION_REFRESH_EACH_REQUEST = True #每次请求过来都刷新session,就不会存在session['user_info']['k'] =v不能修改的问题了,如果不写这一句,需要在修改之后加上一个session['modified']= True SESSION_TYPE = 'redis' # 正式环境连接redis class ProductionConfig(Config): SESSION_REDIS = Redis(host='192.168.0.11',port='6379') #开发环境 class DevelopmentConfig(Config): SESSION_REDIS = Redis(host='127.0.0.1',port='6379') class TestingConfig(Config): pass
from flask_pro import create_app app = create_app() if __name__ == '__main__': app.run()
from flask import Flask from .views import account from .views import home # from flask.ext.session import Session from flask_session import Session def create_app(): app = Flask(__name__) #引入配置文件settings app.config.from_object("settings.DevelopmentConfig") #引入配置文件 app.register_blueprint(account.account) app.register_blueprint(home.home) # 将默认使用的session替换成redis session Session(app) return app
from flask import Blueprint,request,render_template,session,redirect from uuid import uuid4 account = Blueprint('account',__name__) @account.route('/login',methods=['GET','POST']) def login(): if request.method == "GET": return render_template('login.html') user = request.form.get('user') pwd = request.form.get('pwd') print(user,pwd) if user=='alex' and pwd=='123': uid = str(uuid4()) session.permanent=True #flask默认的session中该值默认是Flase,如果不设置,虽然在配置文件中设置了每次请求刷新session,依然是不能对session字典中的元素进行修改 #flask-session中这个值默认是True,的 session['user_info'] = {'id':uid,'name':user} print(session['user_info']) session['user_info']['name']='huahua' # session['modified'] = True #一般不用这种方式,虽然这种方式也可以实现,但在配置中写SESSION_REFRESH_EACH_REQUEST=True这种方式更好, print(session['user_info']) return redirect('/index') else: return render_template('login.html',msg="用户名或密码错误")
from flask import Blueprint,request,render_template,session,redirect home = Blueprint('home',__name__) @home.route('/index') def index(): user_info= session.get('user_info') print(user_info) return render_template('index.html')
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>用户登录</title> </head> <body> <form action="" method="post"> <input type="text" name="user"> <input type="password" name="pwd"> <input type="submit" value="提交 "> {{msg}} </form> </body> </html>