class Session(object): """ セッション管理をするクラス cachelibの機能を使ってファイルによってセッションを管理する セッション自体は1つの辞書っぽいもので,一番上のキーが各セッションのIDになるえ Flask Sessionの実装を参考に作成した https://github.com/fengsp/flask-session/blob/a88f07e7260ae582b0744de42e77c4625e6884ea/flask_session/sessions.py TODO: セッション情報を削除する機能を追加 """ def __init__(self, config: Config): self.cache = FileSystemCache(config.session_cache_dir) self.session_lifetime = config.session_lifetime def get(self, session_id: str) -> Dict[str, Hashable]: """ 与えられたセッションIDのセッション情報を取得する :param session_id: セッションID :return: """ if not session_id: return {} return self._load_session_from_file(session_id) def set(self, key: str, value: Hashable, session_id: str = None) -> str: """ セッションを追加する :param session_id: セッションId :param key: 追加するセッション情報のキー :param value: 追加するセッション情報の値 """ if not session_id: # セッションを新規作成 session_id = self._generate_session_id() session_obj = self._load_session_from_file(session_id) or {} session_obj.update({key: value}) self._save_session(session_id, session_obj) return session_id def destroy(self, session_id): """ セッションを削除する :param session_id: 削除するセッションのID :return: None """ self.cache.delete(session_id) def _load_session_from_file(self, session_id) -> Dict[str, Hashable]: """ 与えられたセッションIDの情報を取得する :param session_id: セッションID :return dict: セッション情報 """ return self.cache.get(session_id) def _save_session(self, session_id: str, obj: Hashable) -> None: self.cache.set(session_id, obj, timeout=self.session_lifetime) def _generate_session_id(self) -> str: return uuid4().hex
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 cachelib.file 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) 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='None')