class FileSystemSessionInterface(SessionInterface): """Uses the :class:`werkzeug.contrib.cache.FileSystemCache` as a session backend. :param cache_dir: the directory where session files are stored. :param threshold: the maximum number of items the session stores before it starts deleting some. :param mode: the file mode wanted for the session files, default 0600 :param key_prefix: A prefix that is added to FileSystemCache store keys. """ session_class = FileSystemSession def __init__(self, cache_dir, threshold, mode, key_prefix): from werkzeug.contrib.cache import FileSystemCache self.cache = FileSystemCache(cache_dir, threshold=threshold, mode=mode) self.key_prefix = key_prefix def _generate_sid(self): return str(uuid4()) 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) data = self.cache.get(self.key_prefix + sid) if data is not None: return self.session_class(data, sid=sid) return self.session_class(sid=sid) 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.cache.delete(self.key_prefix + session.sid) response.delete_cookie(app.session_cookie_name, domain=domain, path=path) return # Modification case. There are upsides and downsides to # emitting a set-cookie header each request. The behavior # is controlled by the :meth:`should_set_cookie` method # which performs a quick check to figure out if the cookie # should be set or not. This is controlled by the # SESSION_REFRESH_EACH_REQUEST config flag as well as # the permanent flag on the session itself. # if not self.should_set_cookie(app, session): # return httponly = self.get_cookie_httponly(app) secure = self.get_cookie_secure(app) expires = self.get_expiration_time(app, session) data = dict(session) self.cache.set(self.key_prefix + session.sid, data, int(app.permanent_session_lifetime.total_seconds())) response.set_cookie(app.session_cookie_name, session.sid, expires=expires, httponly=httponly, domain=domain, path=path, secure=secure)
class FileSystemSessionInterface(SessionInterface): """Uses the :class:`werkzeug.contrib.cache.FileSystemCache` as a session backend. :param cache_dir: the directory where session files are stored. :param threshold: the maximum number of items the session stores before it starts deleting some. :param mode: the file mode wanted for the session files, default 0600 :param key_prefix: A prefix that is added to FileSystemCache store keys. """ session_class = FileSystemSession def __init__(self, cache_dir, threshold, mode, key_prefix): from werkzeug.contrib.cache import FileSystemCache self.cache = FileSystemCache(cache_dir, threshold=threshold, mode=mode) self.key_prefix = key_prefix def _generate_sid(self): return str(uuid4()) 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) data = self.cache.get(self.key_prefix + sid) if data is not None: return self.session_class(data, sid=sid) return self.session_class(sid=sid) 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.cache.delete(self.key_prefix + session.sid) response.delete_cookie(app.session_cookie_name, domain=domain, path=path) return # Modification case. There are upsides and downsides to # emitting a set-cookie header each request. The behavior # is controlled by the :meth:`should_set_cookie` method # which performs a quick check to figure out if the cookie # should be set or not. This is controlled by the # SESSION_REFRESH_EACH_REQUEST config flag as well as # the permanent flag on the session itself. #if not self.should_set_cookie(app, session): # return httponly = self.get_cookie_httponly(app) secure = self.get_cookie_secure(app) expires = self.get_expiration_time(app, session) data = dict(session) self.cache.set(self.key_prefix + session.sid, data, int(app.permanent_session_lifetime.total_seconds())) response.set_cookie(app.session_cookie_name, session.sid, expires=expires, httponly=httponly, domain=domain, path=path, secure=secure)
class WechatCache(WechatSogouBase): """基于文件的缓存 """ def __init__(self, cache_dir='cache', default_timeout=300): """初始化 cache_dir是缓存目录 """ self.cache = FileSystemCache(cache_dir, default_timeout=default_timeout) def clear(self): """清空缓存 """ return self.cache.clear() def get(self, key): """获取缓存 获取键值key的缓存值 如果没有对应缓存,返回None """ return self.cache.get(key) def add(self, key, value, timeout=None): """增加缓存 如果键值key对应的缓存不存在,那么增加值value到键值key,过期时间timeout,默认300秒 否则返回False(即不能覆盖设置缓存) """ return self.cache.add(key, value, timeout) def set(self, key, value, timeout=None): """设置缓存 设置键值key的缓存为value,过期时间300秒 """ return self.cache.set(key, value, timeout) def delete(self, key): """删除缓存 删除键值key存储的缓存 """ return self.cache.delete(key)
class WechatCache(object): """基于文件的缓存 """ def __init__(self, cache_dir='cache', default_timeout=300): """初始化 cache_dir是缓存目录 """ self.cache = FileSystemCache(cache_dir, default_timeout=default_timeout) def clear(self): """清空缓存 """ return self.cache.clear() def get(self, key): """获取缓存 获取键值key的缓存值 如果没有对应缓存,返回None """ return self.cache.get(key) def add(self, key, value, timeout=None): """增加缓存 如果键值key对应的缓存不存在,那么增加值value到键值key,过期时间timeout,默认300秒 否则返回False(即不能覆盖设置缓存) """ return self.cache.add(key, value, timeout) def set(self, key, value, timeout=None): """设置缓存 设置键值key的缓存为value,过期时间300秒 """ return self.cache.set(key, value, timeout) def delete(self, key): """删除缓存 删除键值key存储的缓存 """ return self.cache.delete(key)
class WechatCache: def __init__(self, cache_dir='cache', default_timeout=300): self.cache = FileSystemCache(cache_dir=cache_dir, default_timeout=default_timeout) def clear(self): return self.cache.clear() def get(self, key): return self.cache.get(key) def add(self, key, value, timeout=None): return self.cache.add(key, value, timeout) def set(self, key, value, timeout=None): return self.cache.set(key, value, timeout) def delete(self, key): return self.cache.delete(key)
class FileSystemSessionInterface(SessionInterface): """Uses the :class:`werkzeug.contrib.cache.FileSystemCache` as a session backend. .. versionadded:: 0.2 The `use_signer` parameter was added. :param cache_dir: the directory where session files are stored. :param threshold: the maximum number of items the session stores before it starts deleting some. :param mode: the file mode wanted for the session files, default 0600 :param key_prefix: A prefix that is added to FileSystemCache store keys. :param use_signer: Whether to sign the session id cookie or not. :param permanent: Whether to use permanent session or not. """ session_class = FileSystemSession def __init__(self, cache_dir, threshold, mode, key_prefix, use_signer=False, permanent=True): from werkzeug.contrib.cache import FileSystemCache self.cache = FileSystemCache(cache_dir, threshold=threshold, mode=mode) 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) data = self.cache.get(self.key_prefix + sid) if data is not None: return self.session_class(data, sid=sid) 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.cache.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) samesite = self.get_cookie_samesite(app) data = dict(session) self.cache.set(self.key_prefix + session.sid, data, 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, samesite=samesite)
class FileSystemSessionInterface(SessionInterface): """Uses the :class:`werkzeug.contrib.cache.FileSystemCache` as a session backend. .. versionadded:: 0.2 The `use_signer` parameter was added. :param cache_dir: the directory where session files are stored. :param threshold: the maximum number of items the session stores before it starts deleting some. :param mode: the file mode wanted for the session files, default 0600 :param key_prefix: A prefix that is added to FileSystemCache store keys. :param use_signer: Whether to sign the session id cookie or not. :param permanent: Whether to use permanent session or not. """ session_class = FileSystemSession def __init__(self, cache_dir, threshold, mode, key_prefix, use_signer=False, permanent=True): from werkzeug.contrib.cache import FileSystemCache self.cache = FileSystemCache(cache_dir, threshold=threshold, mode=mode) 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 = signer.unsign(sid) except BadSignature: sid = self._generate_sid() return self.session_class(sid=sid, permanent=self.permanent) data = self.cache.get(self.key_prefix + sid) if data is not None: return self.session_class(data, sid=sid) 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.cache.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) data = dict(session) self.cache.set(self.key_prefix + session.sid, data, total_seconds(app.permanent_session_lifetime)) if self.use_signer: session_id = self._get_signer(app).sign(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)
class Cache(object): """Cache module based on werkzeug.contrib.cache. This is a mixed version of NullCache, SimpleCache, FileSystemCache, MemcachedCache, and RedisCache. :param app: Flask app instance. :param config_prefix: Define a prefix for Flask app config. :param kwargs: Extra parameters. You need to configure a type of the cache, and its related configurations. The default ``config_prefix`` is ``AUTHLIB``, so it requires a config of:: AUTHLIB_CACHE_TYPE = 'simple' If ``config_prefix`` is something else, like ``EXAMPLE``, it would be:: EXAMPLE_CACHE_TYPE = 'simple' The available cache types are: * null: It will not cache anything. No configuration. * simple: It caches things in memory. The only configuration is ``threshold``:: AUTHLIB_CACHE_THRESHOLD = 500 * memcache: It caches things in Memcache. Available configurations:: AUTHLIB_CACHE_MEMCACHED_SERVERS = [] AUTHLIB_CACHE_KEY_PREFIX = None * redis: It caches things in Redis. Available configurations:: AUTHLIB_CACHE_REDIS_HOST = 'localhost' AUTHLIB_CACHE_REDIS_PORT = 6379 AUTHLIB_CACHE_REDIS_PASSWORD = None AUTHLIB_CACHE_REDIS_DB = 0 AUTHLIB_CACHE_KEY_PREFIX = None * filesystem: It caches things in local filesystem. Available configurations:: AUTHLIB_CACHE_DIR = '' # required AUTHLIB_CACHE_THRESHOLD = 500 """ def __init__(self, app, config_prefix='AUTHLIB', **kwargs): deprecate(DEPRECATE_MESSAGE, 0.7) self.config_prefix = config_prefix self.config = app.config cache_type = self._config('type') kwargs.update( dict(default_timeout=self._config('DEFAULT_TIMEOUT', 100))) if cache_type == 'null': self.cache = NullCache() elif cache_type == 'simple': kwargs.update(dict(threshold=self._config('threshold', 500))) self.cache = SimpleCache(**kwargs) elif cache_type == 'memcache': kwargs.update( dict( servers=self._config('MEMCACHED_SERVERS'), key_prefix=self._config('KEY_PREFIX', None), )) self.cache = MemcachedCache(**kwargs) elif cache_type == 'redis': kwargs.update( dict( host=self._config('REDIS_HOST', 'localhost'), port=self._config('REDIS_PORT', 6379), password=self._config('REDIS_PASSWORD', None), db=self._config('REDIS_DB', 0), key_prefix=self._config('KEY_PREFIX', None), )) self.cache = RedisCache(**kwargs) elif cache_type == 'filesystem': kwargs.update(dict(threshold=self._config('threshold', 500), )) self.cache = FileSystemCache(self._config('DIR'), **kwargs) else: raise RuntimeError('`%s` is not a valid cache type!' % cache_type) app.extensions[config_prefix.lower() + '_cache'] = self.cache def _config(self, key, default=_missing): key = key.upper() prior = '%s_CACHE_%s' % (self.config_prefix, key) if prior in self.config: return self.config[prior] fallback = 'CACHE_%s' % key if fallback in self.config: return self.config[fallback] if default is _missing: raise RuntimeError('%s is missing.' % prior) return default def get(self, key): """Look up key in the cache and return the value for it. :param key: the key to be looked up. :returns: The value if it exists and is readable, else ``None``. """ return self.cache.get(key) def delete(self, key): """Delete `key` from the cache. :param key: the key to delete. :returns: Whether the key existed and has been deleted. """ return self.cache.delete(key) def get_many(self, *keys): """Returns a list of values for the given keys. For each key a item in the list is created:: foo, bar = cache.get_many("foo", "bar") Has the same error handling as :meth:`get`. :param keys: The function accepts multiple keys as positional arguments. """ return [self.cache.get(k) for k in keys] def get_dict(self, *keys): """Like :meth:`get_many` but return a dict:: d = cache.get_dict("foo", "bar") foo = d["foo"] bar = d["bar"] :param keys: The function accepts multiple keys as positional arguments. """ return self.cache.get_dict(*keys) def set(self, key, value, timeout=None): """Add a new key/value to the cache (overwrites value, if key already exists in the cache). :param key: the key to set :param value: the value for the key :param timeout: the cache timeout for the key in seconds (if not specified, it uses the default timeout). A timeout of 0 idicates that the cache never expires. :returns: ``True`` if key has been updated, ``False`` for backend errors. Pickling errors, however, will raise a subclass of ``pickle.PickleError``. """ return self.cache.set(key, value, timeout) def add(self, key, value, timeout=None): """Works like :meth:`set` but does not overwrite the values of already existing keys. :param key: the key to set :param value: the value for the key :param timeout: the cache timeout for the key in seconds (if not specified, it uses the default timeout). A timeout of 0 idicates that the cache never expires. :returns: Same as :meth:`set`, but also ``False`` for already existing keys. """ return self.cache.add(key, value, timeout) def set_many(self, mapping, timeout=None): """Sets multiple keys and values from a mapping. :param mapping: a mapping with the keys/values to set. :param timeout: the cache timeout for the key in seconds (if not specified, it uses the default timeout). A timeout of 0 idicates that the cache never expires. :returns: Whether all given keys have been set. """ return self.cache.set_many(mapping, timeout) def delete_many(self, *keys): """Deletes multiple keys at once. :param keys: The function accepts multiple keys as positional arguments. :returns: Whether all given keys have been deleted. :rtype: boolean """ return self.cache.delete_many(*keys) def has(self, key): """Checks if a key exists in the cache without returning it. This is a cheap operation that bypasses loading the actual data on the backend. This method is optional and may not be implemented on all caches. :param key: the key to check """ return self.cache.has(key) def clear(self): """Clears the cache. Keep in mind that not all caches support completely clearing the cache. :returns: Whether the cache has been cleared. """ return self.cache.clear() def inc(self, key, delta=1): """Increments the value of a key by `delta`. If the key does not yet exist it is initialized with `delta`. For supporting caches this is an atomic operation. :param key: the key to increment. :param delta: the delta to add. :returns: The new value or ``None`` for backend errors. """ return self.cache.inc(key, delta=delta) def dec(self, key, delta=1): """Decrements the value of a key by `delta`. If the key does not yet exist it is initialized with `-delta`. For supporting caches this is an atomic operation. :param key: the key to increment. :param delta: the delta to subtract. :returns: The new value or `None` for backend errors. """ return self.cache.dec(key, delta=delta)
class Cache(object): """ This class is used to control the cache objects. If TESTING is True it will use NullCache. """ def __init__(self, app=None): self.cache = None if app is not None: self.init_app(app) else: self.app = None def init_app(self, app): "This is used to initialize cache with your app object" app.config.setdefault('CACHE_DEFAULT_TIMEOUT', 300) app.config.setdefault('CACHE_THRESHOLD', 500) app.config.setdefault('CACHE_KEY_PREFIX', None) app.config.setdefault('CACHE_MEMCACHED_SERVERS', None) app.config.setdefault('CACHE_DIR', None) app.config.setdefault('CACHE_TYPE', 'NullCache') self.app = app self._set_cache() def _set_cache(self): if self.app.config['TESTING']: self.cache = NullCache() else: if self.app.config['CACHE_TYPE'] == 'Null': self.cache = NullCache() elif self.app.config['CACHE_TYPE'] == 'Simple': self.cache = SimpleCache( threshold=self.app.config['CACHE_THRESHOLD'], default_timeout=self.app.config['CACHE_DEFAULT_TIMEOUT']) elif self.app.config['CACHE_TYPE'] == 'Memcached': self.cache = MemcachedCache( self.app.config['CACHE_MEMCACHED_SERVERS'], default_timeout=self.app.config['CACHE_DEFAULT_TIMEOUT'], key_prefix=self.app.config['CACHE_KEY_PREFIX']) elif self.app.config['CACHE_TYPE'] == 'GAE': self.cache = GAEMemcachedCache( default_timeout=self.app.config['CACHE_DEFAULT_TIMEOUT'], key_prefix=self.app.config['CACHE_KEY_PREFIX']) elif self.app.config['CACHE_TYPE'] == 'FileSystem': self.cache = FileSystemCache( self.app.config['CACHE_DIR'], threshold=self.app.config['CACHE_THRESHOLD'], default_timeout=self.app.config['CACHE_DEFAULT_TIMEOUT']) def get(self, *args, **kwargs): "Proxy function for internal cache object." return self.cache.get(*args, **kwargs) def set(self, *args, **kwargs): "Proxy function for internal cache object." self.cache.set(*args, **kwargs) def add(self, *args, **kwargs): "Proxy function for internal cache object." self.cache.add(*args, **kwargs) def delete(self, *args, **kwargs): "Proxy function for internal cache object." self.cache.delete(*args, **kwargs) def cached(self, timeout=None, key_prefix='view/%s', unless=None): """ Decorator. Use this to cache a function. By default the cache key is `view/request.path`. You are able to use this decorator with any function by changing the `key_prefix`. If the token `%s` is located within the `key_prefix` then it will replace that with `request.path` Example:: # An example view function @cache.cached(timeout=50) def big_foo(): return big_bar_calc() # An example misc function to cache. @cache.cached(key_prefix='MyCachedList') def get_list(): return [random.randrange(0, 1) for i in range(50000)] .. code-block:: pycon >>> my_list = get_list() :param timeout: Default None. If set to an integer, will cache for that amount of time. :param key_prefix: Default 'view/%(request.path)s'. Beginning key to . use for the cache key. :param unless: Default None. Cache will *always* execute the caching facilities unless this callable is true. This will bypass the caching entirely. """ def decorator(f): @wraps(f) def decorated_function(*args, **kwargs): #: Bypass the cache entirely. if callable(unless) and unless() is True: return f(*args, **kwargs) if '%s' in key_prefix: cache_key = key_prefix % request.path else: cache_key = key_prefix rv = self.cache.get(cache_key) if not rv or current_app.debug: rv = f(*args, **kwargs) self.cache.set(cache_key, rv, timeout=timeout) return rv return decorated_function return decorator def memoize(self, timeout=None): """ Use this to cache the result of a function, taking its arguments into account in the cache key. Information on `Memoization <http://en.wikipedia.org/wiki/Memoization>`_. Example:: @cache.memoize(timeout=50) def big_foo(a, b): return a + b + random.randrange(0, 1000) .. code-block:: pycon >>> big_foo(5, 2) 753 >>> big_foo(5, 3) 234 >>> big_foo(5, 2) 753 :param timeout: Default None. If set to an integer, will cache for that amount of time. """ def memoize(f): @wraps(f) def decorated_function(*args, **kwargs): cache_key = (f.__name__, id(f), args, str(kwargs)) rv = self.cache.get(cache_key) if rv is None: rv = f(*args, **kwargs) self.cache.set(cache_key, rv) return rv return decorated_function return memoize
class FileSystemSessionInterface(SessionInterface): """Uses the :class:`werkzeug.contrib.cache.FileSystemCache` as a session backend. .. versionadded:: 0.2 The `use_signer` parameter was added. :param cache_dir: the directory where session files are stored. :param threshold: the maximum number of items the session stores before it starts deleting some. :param mode: the file mode wanted for the session files, default 0600 :param key_prefix: A prefix that is added to FileSystemCache store keys. :param use_signer: Whether to sign the session id cookie or not. """ session_class = FileSystemSession def __init__(self, cache_dir, threshold, mode, key_prefix, use_signer=False): from werkzeug.contrib.cache import FileSystemCache self.cache = FileSystemCache(cache_dir, threshold=threshold, mode=mode) #FileSystemCache是从上句导入的,threshold代表最多纪录条数 self.key_prefix = key_prefix self.use_signer = use_signer 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) if self.use_signer: signer = self._get_signer(app) if signer is None: return None try: sid = signer.unsign(sid) except BadSignature: sid = None data = self.cache.get(self.key_prefix + sid) #这是根据session_id获取session值 if data is not None: return self.session_class(data, sid=sid) return self.session_class(sid=sid) def save_session(self, app, session, response): domain = self.get_cookie_domain(app) path = self.get_cookie_path(app) if not session: #验证过了,就是判断session是否为空(空字典) if session.modified: self.cache.delete(self.key_prefix + session.sid) response.delete_cookie(app.session_cookie_name, domain=domain, path=path) return # Modification case. There are upsides and downsides to # emitting a set-cookie header each request. The behavior # is controlled by the :meth:`should_set_cookie` method # which performs a quick check to figure out if the cookie # should be set or not. This is controlled by the # SESSION_REFRESH_EACH_REQUEST config flag as well as # the permanent flag on the session itself. #if not self.should_set_cookie(app, session): # return httponly = self.get_cookie_httponly(app) secure = self.get_cookie_secure(app) expires = self.get_expiration_time(app, session) #data = dict(session) #self.cache.set(self.key_prefix + session.sid, data, # int(app.permanent_session_lifetime.total_seconds())) if self.use_signer: #签名加密 session_id = self._get_signer(app).sign(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) def save_session_without_response(self, app, session): #httponly = self.get_cookie_httponly(app) #secure = self.get_cookie_secure(app) #expires = self.get_expiration_time(app, session) data = dict(session) self.cache.set(self.key_prefix + session.sid, data, int(app.permanent_session_lifetime.total_seconds())) def judge_attack(self, app, request): #判断两次间隔的访问是否大于三秒 sid = request.cookies.get(app.session_cookie_name) if not sid: return False current_time = time.time() try: last_time = self.cache.get(self.key_prefix + sid)['time'] #这是根据session_id获取session值 except: return False if current_time-last_time < 3: return True return False