sirochild commited on
Commit
06c930f
·
verified ·
1 Parent(s): 9b84eb2

Upload persistent_user_manager.py

Browse files
Files changed (1) hide show
  1. persistent_user_manager.py +58 -52
persistent_user_manager.py CHANGED
@@ -57,38 +57,45 @@ class PersistentUserManager:
57
  logger.warning(f"フォールバック: ローカルディレクトリを使用 {self.user_data_dir}")
58
 
59
  def _ensure_cookie_manager(self, force_init: bool = False):
60
- """Cookie管理システムの初期化(ブラウザごとに一度だけ)"""
61
  # 既に初期化済みで、強制初期化でない場合はスキップ
62
- if self._cookie_initialized and not force_init:
63
  return
64
 
65
  # ブラウザセッション単位でのCookie初期化チェック
66
  browser_session_key = f"cookie_initialized_{id(st.session_state)}"
67
- if not force_init and st.session_state.get(browser_session_key, False):
68
  self._cookie_initialized = True
69
  return
70
 
71
  try:
72
- logger.info("永続Cookie管理システム初期化開始(ブラウザセッション単位)...")
73
 
74
  # セキュアなパスワードを生成(環境変数から取得、なければ生成)
75
  cookie_password = os.getenv("MARI_COOKIE_PASSWORD", "mari_chat_secure_key_2024")
76
 
77
- # 永続的なHTTPOnlyクッキー設定でEncryptedCookieManagerを初期化
78
  cookies = EncryptedCookieManager(
79
  prefix="mari_",
80
- password=cookie_password,
81
- # 永続化設定
82
- expiry_days=self.cookie_expiry_days, # 30日間有効
83
- # セキュリティ設定
84
- key_len=32, # より強力な暗号化キー
85
- # HTTPOnly設定(可能な場合)
86
  )
87
 
88
- # Cookieが準備できるまで待機
 
 
 
 
 
 
 
 
 
89
  if not cookies.ready():
90
- logger.warning("永続Cookie準備中 - 待機")
91
- st.stop()
 
 
 
92
 
93
  self.cookies = cookies
94
  self._cookie_initialized = True
@@ -96,7 +103,9 @@ class PersistentUserManager:
96
  # ブラウザセッション単位でフラグを設定
97
  st.session_state[browser_session_key] = True
98
 
99
- logger.info("永続Cookie管理システム初期化完了(HTTPOnly, 365日間有効)")
 
 
100
 
101
  except Exception as e:
102
  logger.error(f"Cookie管理初期化エラー: {e}")
@@ -129,14 +138,7 @@ class PersistentUserManager:
129
  st.session_state.user_id_processing = True
130
 
131
  try:
132
- # フルリセット時以外で、既にセッション状態にuser_idがある場合はそれを使用
133
- if not force_reset and 'user_id' in st.session_state:
134
- existing_id = st.session_state.user_id
135
- if existing_id and self._is_valid_uuid(existing_id):
136
- logger.debug(f"セッション状態からユーザーID使用: {existing_id[:8]}...")
137
- return existing_id
138
-
139
- # Cookie管理システムを初期化(ブラウザごとに一度だけ)
140
  self._ensure_cookie_manager(force_init=force_reset)
141
 
142
  # 1. CookieからユーザーIDを取得(最優先)
@@ -146,9 +148,18 @@ class PersistentUserManager:
146
  # 有効なCookieベースのユーザーIDが存在
147
  self._update_user_access_time(user_id)
148
  st.session_state.user_id = user_id # セッション状態に保存
149
- logger.info(f"Cookie認証成功: {user_id[:8]}...")
150
  return user_id
151
 
 
 
 
 
 
 
 
 
 
152
  # 2. Cookieが無効または存在しない場合は新規作成
153
  if force_reset or not user_id:
154
  user_id = self._create_new_user_with_cookie()
@@ -183,7 +194,7 @@ class PersistentUserManager:
183
  return temp_id
184
 
185
  def _get_user_id_from_cookie(self) -> Optional[str]:
186
- """CookieからユーザーIDを取得"""
187
  try:
188
  # Cookie管理の初期化(初回のみ)
189
  self._ensure_cookie_manager()
@@ -192,10 +203,25 @@ class PersistentUserManager:
192
  logger.debug("Cookie管理システム無効 - None返却")
193
  return None
194
 
 
 
 
 
 
 
 
 
 
195
  user_id = self.cookies.get(self.cookie_name)
196
- if user_id and self._is_valid_uuid(user_id):
197
- logger.debug(f"CookieからユーザーID取得: {user_id[:8]}...")
198
- return user_id
 
 
 
 
 
 
199
 
200
  logger.debug("Cookie内に有効なユーザーIDなし")
201
  return None
@@ -205,7 +231,7 @@ class PersistentUserManager:
205
  return None
206
 
207
  def _set_user_id_cookie(self, user_id: str):
208
- """ユーザーIDを永続的なHTTPOnlyクッキーに設定"""
209
  try:
210
  # Cookie管理システムが初期化されていない場合はスキップ
211
  if not self._cookie_initialized:
@@ -216,33 +242,13 @@ class PersistentUserManager:
216
  logger.debug("Cookie管理システム無効 - Cookie設定スキップ")
217
  return
218
 
219
- # 永続的なCookieの有効期限を設定(30日間)
220
- expiry_date = datetime.now() + timedelta(days=self.cookie_expiry_days)
221
-
222
- # HTTPOnlyと永続化の設定
223
  self.cookies[self.cookie_name] = user_id
224
 
225
- # 永続化のためのCookie属性を設定
226
- # streamlit-cookies-managerは内部的にHTTPOnlyを設定するが、
227
- # より確実にするために明示的に設定
228
- try:
229
- # Cookieの詳細設定(可能な場合)
230
- if hasattr(self.cookies, '_set_cookie_attributes'):
231
- self.cookies._set_cookie_attributes(
232
- name=self.cookie_name,
233
- value=user_id,
234
- expires=expiry_date,
235
- httponly=True,
236
- secure=True, # HTTPS環境では必須
237
- samesite='Lax' # CSRF攻撃を防ぐ
238
- )
239
- except Exception as attr_e:
240
- logger.debug(f"Cookie属性設定エラー(通常動作に影響なし): {attr_e}")
241
-
242
- # Cookieを保存
243
  self.cookies.save()
244
 
245
- logger.info(f"永続的なHTTPOnlyクッキーに保存: {user_id[:8]}... (有効期限: {self.cookie_expiry_days}日間)")
246
 
247
  except Exception as e:
248
  logger.warning(f"永続Cookie設定エラー: {e}")
 
57
  logger.warning(f"フォールバック: ローカルディレクトリを使用 {self.user_data_dir}")
58
 
59
  def _ensure_cookie_manager(self, force_init: bool = False):
60
+ """Cookie管理システムの初期化(永続Cookie対応)"""
61
  # 既に初期化済みで、強制初期化でない場合はスキップ
62
+ if self._cookie_initialized and not force_init and self.cookies is not None:
63
  return
64
 
65
  # ブラウザセッション単位でのCookie初期化チェック
66
  browser_session_key = f"cookie_initialized_{id(st.session_state)}"
67
+ if not force_init and st.session_state.get(browser_session_key, False) and self.cookies is not None:
68
  self._cookie_initialized = True
69
  return
70
 
71
  try:
72
+ logger.info("永続Cookie管理システム初期化開始...")
73
 
74
  # セキュアなパスワードを生成(環境変数から取得、なければ生成)
75
  cookie_password = os.getenv("MARI_COOKIE_PASSWORD", "mari_chat_secure_key_2024")
76
 
77
+ # EncryptedCookieManagerを初期化(永続Cookie対応)
78
  cookies = EncryptedCookieManager(
79
  prefix="mari_",
80
+ password=cookie_password
 
 
 
 
 
81
  )
82
 
83
+ # Cookieが準備できるまで待機(最大3回試行)
84
+ max_attempts = 3
85
+ for attempt in range(max_attempts):
86
+ if cookies.ready():
87
+ break
88
+ logger.debug(f"Cookie準備待機中... ({attempt + 1}/{max_attempts})")
89
+ if attempt < max_attempts - 1:
90
+ import time
91
+ time.sleep(0.1)
92
+
93
  if not cookies.ready():
94
+ logger.warning("Cookie準備タイムアウト - フォールバックモード")
95
+ self.cookies = None
96
+ self._cookie_initialized = True
97
+ st.session_state[browser_session_key] = True
98
+ return
99
 
100
  self.cookies = cookies
101
  self._cookie_initialized = True
 
103
  # ブラウザセッション単位でフラグを設定
104
  st.session_state[browser_session_key] = True
105
 
106
+ # 既存Cookieの確認
107
+ existing_cookies = dict(self.cookies)
108
+ logger.info(f"永続Cookie管理システム初期化完了 - 既存Cookie数: {len(existing_cookies)}")
109
 
110
  except Exception as e:
111
  logger.error(f"Cookie管理初期化エラー: {e}")
 
138
  st.session_state.user_id_processing = True
139
 
140
  try:
141
+ # Cookie管理システムを初期化(最優先)
 
 
 
 
 
 
 
142
  self._ensure_cookie_manager(force_init=force_reset)
143
 
144
  # 1. CookieからユーザーIDを取得(最優先)
 
148
  # 有効なCookieベースのユーザーIDが存在
149
  self._update_user_access_time(user_id)
150
  st.session_state.user_id = user_id # セッション状態に保存
151
+ logger.info(f"永続Cookie認証成功: {user_id[:8]}...")
152
  return user_id
153
 
154
+ # 2. フルリセット時以外で、セッション状態にuser_idがある場合はCookieと照合
155
+ if not force_reset and 'user_id' in st.session_state:
156
+ existing_id = st.session_state.user_id
157
+ if existing_id and self._is_valid_uuid(existing_id) and self._is_valid_user_id(existing_id):
158
+ # セッション状態のIDが有効な場合、Cookieにも保存
159
+ self._set_user_id_cookie(existing_id)
160
+ logger.info(f"セッション状態からユーザーID復元: {existing_id[:8]}...")
161
+ return existing_id
162
+
163
  # 2. Cookieが無効または存在しない場合は新規作成
164
  if force_reset or not user_id:
165
  user_id = self._create_new_user_with_cookie()
 
194
  return temp_id
195
 
196
  def _get_user_id_from_cookie(self) -> Optional[str]:
197
+ """CookieからユーザーIDを取得(永続Cookie対応)"""
198
  try:
199
  # Cookie管理の初期化(初回のみ)
200
  self._ensure_cookie_manager()
 
203
  logger.debug("Cookie管理システム無効 - None返却")
204
  return None
205
 
206
+ # Cookieが準備完了するまで待機
207
+ if not self.cookies.ready():
208
+ logger.debug("Cookie準備中 - 待機")
209
+ return None
210
+
211
+ # 全てのCookieを確認(デバッグ用)
212
+ all_cookies = dict(self.cookies)
213
+ logger.debug(f"利用可能なCookie: {list(all_cookies.keys())}")
214
+
215
  user_id = self.cookies.get(self.cookie_name)
216
+ if user_id:
217
+ logger.debug(f"Cookie値取得: {user_id[:8] if len(user_id) >= 8 else user_id}...")
218
+
219
+ if self._is_valid_uuid(user_id):
220
+ logger.info(f"永続CookieからユーザーID取得成功: {user_id[:8]}...")
221
+ return user_id
222
+ else:
223
+ logger.warning(f"Cookie内のユーザーIDが無効な形式: {user_id}")
224
+ return None
225
 
226
  logger.debug("Cookie内に有効なユーザーIDなし")
227
  return None
 
231
  return None
232
 
233
  def _set_user_id_cookie(self, user_id: str):
234
+ """ユーザーIDを永続的なクッキーに設定"""
235
  try:
236
  # Cookie管理システムが初期化されていない場合はスキップ
237
  if not self._cookie_initialized:
 
242
  logger.debug("Cookie管理システム無効 - Cookie設定スキップ")
243
  return
244
 
245
+ # 永続的なCookieを設定
 
 
 
246
  self.cookies[self.cookie_name] = user_id
247
 
248
+ # Cookieを保存(streamlit-cookies-managerは自動的に永続化される)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
249
  self.cookies.save()
250
 
251
+ logger.info(f"永続クッキーに保存: {user_id[:8]}... (ブラウザ閉じても保持)")
252
 
253
  except Exception as e:
254
  logger.warning(f"永続Cookie設定エラー: {e}")