flask session组件的使用示例

一、简介

flask中session组件可分为内置的session组件还有第三方flask-session组件,内置的session组件功能单一,而第三方的flask-sessoin可支持redis、memcached、文件等进行session的存储。以下将介绍内置session以及第三方session组件的使用方法以及处理机制。

二、内置session处理机制

Cookie与Session

Cookie:

Cookie意为“甜饼”,是由W3C组织提出,最早由Netscape社区发展的一种机制。目前Cookie已经成为标准,所有的主流浏览器如IE、Netscape、Firefox、Opera等都支持Cookie。由于HTTP是一种无状态的协议,服务器单从网络连接上无从知道客户身份。怎么办呢?就给客户端们颁发一个通行证吧,每人一个,无论谁访问都必须携带自己通行证。这样服务器就能从通行证上确认客户身份了。这就是Cookie的工作原理。

Cookie实际上是一小段的文本信息。客户端请求服务器,如果服务器需要记录该用户状态,就使用response向客户端浏览器颁发一个Cookie。客户端浏览器会把Cookie保存起来。当浏览器再请求该网站时,浏览器把请求的网址连同该Cookie一同提交给服务器。服务器检查该Cookie,以此来辨认用户状态。服务器还可以根据需要修改Cookie的内容

Session:

Session是另一种记录客户状态的机制,不同的是Cookie保存在客户端浏览器中,而Session保存在服务器上。客户端浏览器访问服务器的时候,服务器把客户端信息以某种形式记录在服务器上。这就是Session。客户端浏览器再次访问时只需要从该Session中查找该客户的状态就可以了,实质上session就是保存在服务器端的键值对。

如果说Cookie机制是通过检查客户身上的“通行证”来确定客户身份的话,那么Session机制就是通过检查服务器上的“客户明细表”来确认客户身份。Session相当于程序在服务器上建立的一份客户档案,客户来访的时候只需要查询客户档案表就可以了。

第一次请求,session的创建过程

在flask上下文中介绍了,请求到flask框架会执行wsgi_app方法:

def wsgi_app(self, environ, start_response):
 ctx = self.request_context(environ) #实例化生成RequestContext对象
 error = None
 try:
  try:
   ctx.push() #push上下文到LocalStack中
   response = self.full_dispatch_request() #执行视图函数过程
  except Exception as e:
   error = e
   response = self.handle_exception(e) #处理异常
  except:
   error = sys.exc_info()[1]
   raise
  return response(environ, start_response)
 finally:
  if self.should_ignore_error(error):
   error = None
  ctx.auto_pop(error)  # 删除LocalStack中的数据

在改方法中会生成一个ctx也就是RequestContext对象:

class RequestContext(object):
 def __init__(self, app, environ, request=None):
  self.app = app # app对象
  if request is None:
   request = app.request_class(environ)
  self.request = request # 封装request
  self.url_adapter = app.create_url_adapter(self.request)
  self.flashes = None
  self.session = None #一开始的session

在这个对象中封装了session,最初为None。接着在wsgi_app中执行ctx.push:

def push(self):
  app_ctx = _app_ctx_stack.top # 获取app上下文
  if app_ctx is None or app_ctx.app != self.app:
   app_ctx = self.app.app_context() #将app上下文push到app_ctx对于的LocalStack中
   app_ctx.push()
   self._implicit_app_ctx_stack.append(app_ctx)
  else:
   self._implicit_app_ctx_stack.append(None)
  if hasattr(sys, 'exc_clear'):
   sys.exc_clear()
  _request_ctx_stack.push(self)
  if self.session is None: # 判断session是否为None,一开始为None
   session_interface = self.app.session_interface # 获取操作session的对象
   self.session = session_interface.open_session( #调用open_session 创建session
    self.app, self.request
   )
   if self.session is None:
    self.session = session_interface.make_null_session(self.app)

这里我们主要关注session,前面的代码在上下文中已经进行了相关说明,这里有个判断session是否为None,刚开始RequestContext中的session为None,所以条件成立,此时执行以下语句:

session_interface = self.app.session_interface
self.session = session_interface.open_session(
    self.app, self.request
   )
if self.session is None:
 self.session = session_interface.make_null_session(self.app)

首先来看session_interface = self.app.session_interface,self.app.session_interface就是app中的session_interface属性:

session_interface = SecureCookieSessionInterface()

默认是一个SecureCookieSessionInterface()对象,该对象的内部主要实现了open_session和save_session用于使用和保存session。接着self.session被重新赋值为session_interface.open_session(self.app, self.request)方法返回的值,以下为open_session源码:

def open_session(self, app, request):
 s = self.get_signing_serializer(app) #根据app.secret_key获取签名算法
 if s is None:
  return None
 # 根据配置中的session_cookie_name获取session对于的值
 val = request.cookies.get(app.session_cookie_name) #如果request.cookies为空,val为空
 if not val:
  return self.session_class()
 max_age = total_seconds(app.permanent_session_lifetime)
 try:
  data = s.loads(val, max_age=max_age)
  return self.session_class(data)
 except BadSignature:
  return self.session_class()

该方法返回self.session_class(),当请求第一次来时,request.cookies为None,所以val也为None,返回self.session_class(),而session_class又是SecureCookieSession:

session_class = SecureCookieSession

所以我们继续看SecureCookieSession:

class SecureCookieSession(CallbackDict, SessionMixin):
 accessed = False

 def __init__(self, initial=None):
  def on_update(self):
   self.modified = True
   self.accessed = True

  super(SecureCookieSession, self).__init__(initial, on_update)

 def __getitem__(self, key):
  self.accessed = True
  return super(SecureCookieSession, self).__getitem__(key)

 def get(self, key, default=None):
  self.accessed = True
  return super(SecureCookieSession, self).get(key, default)

 def setdefault(self, key, default=None):
  self.accessed = True
  return super(SecureCookieSession, self).setdefault(key, default)

该类继承了CallbackDict, SessionMixin我们继续来看看CallbackDict:

class CallbackDict(UpdateDictMixin, dict):

 """A dict that calls a function passed every time something is changed.
 The function is passed the dict instance.
 """

 def __init__(self, initial=None, on_update=None):
  dict.__init__(self, initial or ())
  self.on_update = on_update

 def __repr__(self):
  return '<%s %s>' % (
   self.__class__.__name__,
   dict.__repr__(self)
  )

也就是说SecureCookieSession继承了CallbackDict而CallbackDict继承了原生的dict,所以我们可以认为SecureCookieSession是一个特殊的字典,是调用了SecureCookieSessionInterface类中open_session返回的特殊字典,经过进一步分析self.session此时就是这个字典,这也意味着session在执行open_session方法时候被创建了,并保存在ctx中,也就是在RequestContext对象中,当我们使用session时候是通过全局变量session = LocalProxy(partial(_lookup_req_object, 'session'))由LocalProxy对象从ctx中获取到session。

第二次请求

开始我们知道session第一次请求来的时候是在open_session方法之后被创建,当第二次请求时,此时在open_session方法中,val已经不在是None,此时获取cookie的有效时长,如果cookie依然有效,通过与写入时同样的签名算法将cookie中的值解密出来并写入字典并返回,若cookie已经失效,则仍然返回'空字典',这样以来在第二次请求中就能获取到之前保存的session数据。

session生命周期

我们介绍了session创建时候是在ctx.push时候开始创建,也就是说在这之后我们就可以使用session,对它进行操作了,那么session什么时候保存呢?我们接下来继续看wsgi_app:

def wsgi_app(self, environ, start_response):
 ctx = self.request_context(environ)
 error = None
 try:
  try:
   ctx.push()
   response = self.full_dispatch_request()
  except Exception as e:
   error = e
   response = self.handle_exception(e)
  except:
   error = sys.exc_info()[1]
   raise
  return response(environ, start_response)
 finally:
  if self.should_ignore_error(error):
   error = None
  ctx.auto_pop(error)

生成session后,接着执行self.full_dispatch_request():

def full_dispatch_request(self):
 """Dispatches the request and on top of that performs request
 pre and postprocessing as well as HTTP exception catching and
 error handling.

 .. versionadded:: 0.7
 """
 self.try_trigger_before_first_request_functions() #执行app.before_first_reques钩子函数
 try:
  request_started.send(self) # 触发request_started信号
  rv = self.preprocess_request() # 执行before_request钩子函数
  if rv is None:
   rv = self.dispatch_request() # 执行视图函数
 except Exception as e:
  rv = self.handle_user_exception(e)
 return self.finalize_request(rv)

这一部分先执行钩子app.before_first_reques在触发request_started信号,再执行before_request钩子函数,然后在执行视图函数,rv是执行完视图函数的返回值,最后执行finalize_request,这里的session保存就发生在这里:

def finalize_request(self, rv, from_error_handler=False):
 response = self.make_response(rv)
 try:
  response = self.process_response(response)
  request_finished.send(self, response=response)
 except Exception:
  if not from_error_handler:
   raise
  self.logger.exception('Request finalizing failed with an '
        'error while handling an error')
 return response

注意这里的在最后会session判断是否为空,会执行save_session方法,也就是SecureCookieSessionInterface的save_session方法:

def save_session(self, app, session, response):
 domain = self.get_cookie_domain(app)
 path = self.get_cookie_path(app)

 # If the session is modified to be empty, remove the cookie.
 # If the session is empty, return without setting the cookie.
 if not session:
  if session.modified:
   response.delete_cookie(
    app.session_cookie_name,
    domain=domain,
    path=path
   )

  return

 # Add a "Vary: Cookie" header if the session was accessed at all.
 if session.accessed:
  response.vary.add('Cookie')

 if not self.should_set_cookie(app, session):
  return

 httponly = self.get_cookie_httponly(app)
 secure = self.get_cookie_secure(app)
 samesite = self.get_cookie_samesite(app)
 expires = self.get_expiration_time(app, session)
 val = self.get_signing_serializer(app).dumps(dict(session))
 response.set_cookie(
  app.session_cookie_name,
  val,
  expires=expires,
  httponly=httponly,
  domain=domain,
  path=path,
  secure=secure,
  samesite=samesite
 )

该方法最后保存的session调用的response.set_cookie,其实是将数据保存在cookie中,也就是在客户端的浏览器中,并非在服务端进行数据的保存,当请求完毕后会执行ctx.auto_pop(error)这时候会从上下文中将session和request删除,到此,session的生命周期结束。

视图函数使用session

在介绍flask的上下文中就已经对session进行过介绍,其本质也是通过LocalProxy操作上下文从而设置session,我们以session['username']='wd'作为列子,首先根据

session = LocalProxy(partial(_lookup_req_object, 'session'))

session是一个LocalProxy对象,执行session['username']=‘wd'则执行LocalProxy对象的__setitem__方法,而__setitem__方法中则是调用_get_current_object获取ctx中的session对象,而其对象本质是一个特殊的字典,相当于在字典中加一对key,value。

小结

flask内置session本质上依靠上下文,当请求到来时,调用session_interface中的open_session方法解密获取session的字典,并保存在RequestContext.session中,也就是上下文中,然后在视图函数执行完毕后调用session_interface的save_session方法,将session以加密的方式写入response的cookie中,浏览器再保存数据。而第三方的session组件原理就是基于是open_session方法和save方法,从而实现session更多的session保存方案。

三、第三方组件flask-session

flask-session支持多种数据库session保存方案如:redis、memchached、mongodb甚至文件系统等。官方文档: https://pythonhosted.org/Flask-Session/

安装:

pip3 install flask-session

redis

import redis
from flask import Flask, session
from flask_session import Session
from datetime import timedelta

app = Flask(__name__)
app.debug = True
app.secret_key = 'adavafa'

app.config['SESSION_TYPE'] = 'redis' # session类型为redis
app.config['SESSION_PERMANENT'] = True # 如果设置为True,则关闭浏览器session就失效。
app.config['PERMANENT_SESSION_LIFETIME']=timedelta(seconds=20)
#一个持久化的会话的生存时间,是一个datetime.timedelta对象,也可以用一个整数来表示秒,前提设置了PERMANENT_SESSION_LIFETIME为True
app.config['SESSION_USE_SIGNER'] = False # 是否对发送到浏览器上session的cookie值进行加密,默认False
app.config['SESSION_KEY_PREFIX'] = 'flask-session' # 保存到redis中的key的前缀
app.config['SESSION_COOKIE_NAME']= 'session_id'  # 保存在浏览器的cookie名称
app.config['SESSION_REDIS'] = redis.Redis(host='10.1.210.33', port=‘6379',password=‘123123') # 用于连接redis的配置

#其他配置,不经常使用
app.config['SESSION_COOKIE_DOMAIN']='127.0.0.1' # 设置cookie的域名,不建议设置默认为server_name
app.config['SESSION_COOKIE_PATH']='/' # 会话cookie的路径。 如果未设置,则cookie将对所有url有效,默认为'/'
app.config['SESSION_COOKIE_HTTPONLY']=True # 是否启动httponly,默认为true,为了防止xss脚本访问cookie

Session(app)
@app.route('/login')
def index():
 session["username"]="jack"
 return 'login'

if __name__ == '__main__':
 app.run()

Memchached

import memcache
from flask import Flask, session
from flask_session import Session
from datetime import timedelta

app = Flask(__name__)
app.debug = True
app.secret_key = 'adavafa'

app.config['SESSION_TYPE'] = ‘memcached' # session类型为memcached
app.config['SESSION_PERMANENT'] = True # 如果设置为True,则关闭浏览器session就失效。
app.config['PERMANENT_SESSION_LIFETIME']=timedelta(seconds=20)
#一个持久化的会话的生存时间,是一个datetime.timedelta对象,也可以用一个整数来表示秒,前提设置了PERMANENT_SESSION_LIFETIME为True
app.config['SESSION_USE_SIGNER'] = False # 是否对发送到浏览器上session的cookie值进行加密,默认False
app.config['SESSION_KEY_PREFIX'] = 'flask-session' # 保存到缓存中的key的前缀
app.config['SESSION_COOKIE_NAME']= 'session_id'  # 保存在浏览器的cookie名称
app.config['SESSION_MEMCACHED'] = memcache.Client(['10.1.210.33:12000']) #连接

#其他配置,不经常使用
app.config['SESSION_COOKIE_DOMAIN']='127.0.0.1' # 设置cookie的域名,不建议设置默认为server_name
app.config['SESSION_COOKIE_PATH']='/' # 会话cookie的路径。 如果未设置,则cookie将对所有url有效,默认为'/'
app.config['SESSION_COOKIE_HTTPONLY']=True # 是否启动httponly,默认为true,为了防止xss脚本访问cookie

Session(app)

@app.route('/login')
def index():
 session["username"]="jack"
 return 'login'

if __name__ == '__main__':
 app.run()

Filesystem

from flask import Flask, session
from flask_session import Session
from datetime import timedelta

app = Flask(__name__)
app.debug = True
app.secret_key = 'adavafa'

app.config['SESSION_TYPE'] = 'filesystem' # session类型为filesystem
app.config['SESSION_FILE_DIR']='/opt/db' #文件保存目录
app.config['SESSION_FILE_THRESHOLD'] = 300 # 存储session的个数如果大于这个值时,开始删除

app.config['SESSION_PERMANENT'] = True # 如果设置为True,则关闭浏览器session就失效。
app.config['PERMANENT_SESSION_LIFETIME']=timedelta(seconds=20)
#一个持久化的会话的生存时间,是一个datetime.timedelta对象,也可以用一个整数来表示秒,前提设置了PERMANENT_SESSION_LIFETIME为True
app.config['SESSION_USE_SIGNER'] = False # 是否对发送到浏览器上session的cookie值进行加密,默认False
app.config['SESSION_KEY_PREFIX'] = 'flask-session' # 保存到文件中的key的前缀
app.config['SESSION_COOKIE_NAME']= 'session_id'  # 保存在浏览器的cookie名称

#其他配置,不经常使用
app.config['SESSION_COOKIE_DOMAIN']='127.0.0.1' # 设置cookie的域名,不建议设置默认为server_name
app.config['SESSION_COOKIE_PATH']='/' # 会话cookie的路径。 如果未设置,则cookie将对所有url有效,默认为'/'
app.config['SESSION_COOKIE_HTTPONLY']=True # 是否启动httponly,默认为true,为了防止xss脚本访问cookie

Session(app)

@app.route('/login')
def index():
 session["username"]="jack"
 return 'login'

if __name__ == '__main__':
 app.run()

mongodb

import pymongo
from flask import Flask, session
from flask_session import Session
from datetime import timedelta

app = Flask(__name__)
app.debug = True
app.secret_key = 'adavafa'

app.config['SESSION_TYPE'] = 'mongodb' # session类型为mongodb
app.config['SESSION_MONGODB'] = pymongo.MongoClient('localhost',27017)
app.config['SESSION_MONGODB_DB'] = '数据库名称'
app.config['SESSION_MONGODB_COLLECT'] = '表名称'

app.config['SESSION_PERMANENT'] = True # 如果设置为True,则关闭浏览器session就失效。
app.config['PERMANENT_SESSION_LIFETIME']=timedelta(seconds=20)
#一个持久化的会话的生存时间,是一个datetime.timedelta对象,也可以用一个整数来表示秒,前提设置了PERMANENT_SESSION_LIFETIME为True
app.config['SESSION_USE_SIGNER'] = False # 是否对发送到浏览器上session的cookie值进行加密,默认False
app.config['SESSION_KEY_PREFIX'] = 'flask-session' # 保存的session的key的前缀
app.config['SESSION_COOKIE_NAME']= 'session_id'  # 保存在浏览器的cookie名称

#其他配置,不经常使用
app.config['SESSION_COOKIE_DOMAIN']='127.0.0.1' # 设置cookie的域名,不建议设置默认为server_name
app.config['SESSION_COOKIE_PATH']='/' # 会话cookie的路径。 如果未设置,则cookie将对所有url有效,默认为'/'
app.config['SESSION_COOKIE_HTTPONLY']=True # 是否启动httponly,默认为true,为了防止xss脚本访问cookie

Session(app)

@app.route('/login')
def index():
 session["username"]="jack"
 return 'login'

if __name__ == '__main__':
 app.run()

sqlalchemy

import redis
from flask import Flask, session
from flask_session import Session
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.debug = True
app.secret_key = 'adavafa'

# 设置数据库链接
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:dev@127.0.0.1:3306/devops?charset=utf8'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
# 实例化SQLAlchemy
db = SQLAlchemy(app)
app.config['SESSION_TYPE'] = 'sqlalchemy' # session类型为sqlalchemy
app.config['SESSION_SQLALCHEMY'] = db # SQLAlchemy对象
app.config['SESSION_SQLALCHEMY_TABLE'] = '表名' # session要保存的表名称

app.config['SESSION_PERMANENT'] = True # 如果设置为True,则关闭浏览器session就失效。
app.config['PERMANENT_SESSION_LIFETIME']=timedelta(seconds=20)
#一个持久化的会话的生存时间,是一个datetime.timedelta对象,也可以用一个整数来表示秒,前提设置了PERMANENT_SESSION_LIFETIME为True
app.config['SESSION_USE_SIGNER'] = False # 是否对发送到浏览器上session的cookie值进行加密,默认False
app.config['SESSION_KEY_PREFIX'] = 'flask-session' # 保存的session的key的前缀
app.config['SESSION_COOKIE_NAME']= 'session_id'  # 保存在浏览器的cookie名称

#其他配置,不经常使用
app.config['SESSION_COOKIE_DOMAIN']='127.0.0.1' # 设置cookie的域名,不建议设置默认为server_name
app.config['SESSION_COOKIE_PATH']='/' # 会话cookie的路径。 如果未设置,则cookie将对所有url有效,默认为'/'
app.config['SESSION_COOKIE_HTTPONLY']=True # 是否启动httponly,默认为true,为了防止xss脚本访问cookie

Session(app)

@app.route('/login')
def index():
 session["username"]="jack"
 return 'login'

if __name__ == '__main__':
 app.run()

###使用SQLAlchemy时候先确保数据库和表都存在
在命令行中创建表
#>>> from app import db
#>>> db.create_all()

原理

这里以redis作为session存储方案做分析,以下是RedisSessionInterface源码:

class RedisSessionInterface(SessionInterface):
 serializer = pickle
 session_class = RedisSession

 def __init__(self, redis, key_prefix, use_signer=False, permanent=True):
  if redis is None:
   from redis import Redis
   redis = Redis()
  self.redis = redis
  self.key_prefix = key_prefix
  self.use_signer = use_signer
  self.permanent = permanent

 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()
    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)

 def save_session(self, app, session, response):
  domain = self.get_cookie_domain(app)
  path = self.get_cookie_path(app)
  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)

分析:RedisSessionInterface继承了SessionInterface

class SessionInterface(FlaskSessionInterface):

 def _generate_sid(self):
  return str(uuid4())

 def _get_signer(self, app):
  if not app.secret_key:
   return None
  return Signer(app.secret_key, salt='flask-session',
      key_derivation='hmac')

而SessionInterface又继承了FlaskSessionInterface,而FlaskSessionInterface又继承了flask内置的SessionInterface,并且RedisSessionInterface重写了内置session的open_session和save_session.

首先是RedisSessionInterface实例化用于初始化配置,例如redis的连接、签名配置、过期配置、前缀配置等。

接下来看两个核心方法:open_session方法和save_session方法。

open_session:

def open_session(self, app, request):
 sid = request.cookies.get(app.session_cookie_name) #获取session id
 if not sid: #判断session id是否为空,为空表示第一次请求
  sid = self._generate_sid() # 返回使用uuid4随机字符串
  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) # 对session id 进行加密签名
   sid = sid_as_bytes.decode()
  except BadSignature:
   sid = self._generate_sid()
   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) # 获取seession数据
 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)

改方法先从cookie中获取session id,然后对session id判断是否为空,为空表示第一次请求,则通过self._generate_sid()返回随机字符串,作为返回给浏览器的sessionid

def _generate_sid(self):
 return str(uuid4())

接着判断签名判断是否为true,然后对session 进行签名,这里和内置session不同的是获取session的时候通过self.redis.get(self.key_prefix + sid)在redis中进行获取。

save_session:

def save_session(self, app, session, response):
 domain = self.get_cookie_domain(app) # 获取cookie中的域名
 path = self.get_cookie_path(app) # 获取cookie 中path
 if not session: # 判断有误session对象
  if session.modified: #没有但是被修改了,表示已经被删除了
   self.redis.delete(self.key_prefix + session.sid) #清空session
   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)) #保存session
 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, # 设置cookie
      expires=expires, httponly=httponly,
      domain=domain, path=path, secure=secure)

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • flask使用session保存登录状态及拦截未登录请求代码

    本文主要研究的是flask使用session保存登录状态及拦截未登录请求的相关内容,具体介绍如下. 前端请求form: <form action="/user/add" method="get"> <input type="text" name="username" value="111"> <input type="submit" value="

  • Flask框架重定向,错误显示,Responses响应及Sessions会话操作示例

    本文实例讲述了Flask框架重定向,错误显示,Responses响应及Sessions会话操作.分享给大家供大家参考,具体如下: 重定向和错误显示 将用户重定向到另一个端点,使用redirect(), 要提前中止错误请求,请使用abort()函数 from flask import abort, redirect, url_for @app.route('/') def index(): return redirect(url_for('login')) @app.route('/login')

  • Flask之flask-session的具体使用

    flask-session是flask框架的session组件,由于原来flask内置session使用签名cookie保存,该组件则将支持session保存到多个地方,如: redis memcached filesystem mongodb sqlalchmey 安装 pip3 install flask-session 存储方式 redis #!/usr/bin/env python # -*- coding:utf-8 - import redis from flask import F

  • Flask框架模板继承实现方法分析

    本文实例讲述了Flask框架模板继承实现方法.分享给大家供大家参考,具体如下: 在模板中,可能会遇到以下情况: 多个模板具有完全相同的顶部和底部内容 多个模板中具有相同的模板代码内容,但是内容中部分值不一样 多个模板中具有完全相同的 html 代码块内容 像遇到这种情况,可以使用 JinJa2 模板中的 继承 来进行实现 模板继承是为了重用模板中的公共内容.一般Web开发中,继承主要使用在网站的顶部菜单.底部.这些内容可以定义在父模板中,子模板直接继承,而不需要重复书写. 标签定义的内容 {%

  • python flask框架实现重定向功能示例

    本文实例讲述了python flask框架实现重定向功能.分享给大家供大家参考,具体如下: flask 重定向: from flask import * app = Flask(__name__) @app.route('/') def index(): return redirect(url_for('login')) @app.route('/login') def login(): return render_template('login.html') if __name__ == '_

  • 在Linux上安装Python的Flask框架和创建第一个app实例的教程

    无论你在linux上娱乐还是工作,这对你而言都是一个使用python来编程的很好的机会.回到大学我希望他们教我的是Python而不是Java,这学起来很有趣且在实际的应用如yum包管理器中很有用. 本篇教程中我会带你使用python和一个称为flask的微型框架来构建一个简单的应用,来显示诸如每个进程的内存使用,CPU百分比之类有用的信息. 前置需求 Python基础.列表.类.函数.模块.HTML/CSS (基础). 学习这篇教程你不必是一个python高级开发者,但是首先我建议你阅读http

  • flask框架jinja2模板与模板继承实例分析

    本文实例讲述了flask框架jinja2模板与模板继承.分享给大家供大家参考,具体如下: jinja2模板 from werkzeug.contrib.cache import SimpleCache from flask import Flask, request, render_template,redirect,abort, url_for CACHE_TIME = 300 cache = SimpleCache() cache.timeout = CACHE_TIME app = Fla

  • Flask框架模板渲染操作简单示例

    本文实例讲述了Flask框架模板渲染操作.分享给大家供大家参考,具体如下: from flask import render_template from flask import Flask from flask import Markup from flask import abort, redirect app = Flask(__name__) @app.route('/') def hello_site(): return "welcome my site!!!!!" #返回给

  • 原生JS实现Ajax跨域请求flask响应内容

    Ajax方法好,网站感觉跟高大上,但由于Js的局限,跨域Ajax无法实现,这里,讲一下解决办法,前提是需要能够自己可以控制flask端的响应. 主要技术: 修改服务器相应的相应头,使其可以相应任意域名.and设置响应头,使其能够相应POST方法. 实现代码: 这里先放flask代码: from flask import make_response @app.route('/test',methods=['get','post']) def Test(): if request.method=='

  • Flask框架响应、调度方法和蓝图操作实例分析

    本文实例讲述了Flask框架响应.调度方法和蓝图操作.分享给大家供大家参考,具体如下: 响应 像现在大部分的互联网应用用的数据传输格式都是JSON,当用户访问一个URL,我们如何通过Flask返回JSON的响应: 普通做法: @app.route("/") def showInfo(): return jsonify({"name":"老王","age":18}) 当我们的应用有大量的URL时,我们需要每次都用jsonify转

  • Flask教程之重定向与错误处理实例分析

    本文实例讲述了Flask教程之重定向与错误处理.分享给大家供大家参考,具体如下: Flask类有一个redirect()方法. 当我们调用它时, 它会返回一个响应对象并且按指定的状态码将用户重定向到另一个位置. redirect()方法的原型如下: Flask.redirect(location, statuscode, response) 在上面的函数中, location 我们要重定向的URL位置 statuscode 状态码会在http头中发送给浏览器, 默认为302 response 用

随机推荐