11"""
22JMComic 认证管理模块
33
4- 提供登录、登出、会话管理等认证功能。
4+ 提供登录、登出、会话管理等认证功能,支持 cookies 持久化 。
55"""
66
7+ import json
8+
79from astrbot .api import logger
810
911from .base import JMClientMixin , JMConfigManager
@@ -29,6 +31,50 @@ def __init__(self, config_manager: JMConfigManager):
2931 self ._username : str | None = None
3032 self ._client = None
3133
34+ # 尝试从 cookies 文件恢复登录状态
35+ self ._try_restore_session ()
36+
37+ def _try_restore_session (self ) -> None :
38+ """尝试从 cookies 文件恢复登录状态"""
39+ cookies_file = self .config .cookies_file
40+ if cookies_file .exists ():
41+ try :
42+ with open (cookies_file , encoding = "utf-8" ) as f :
43+ data = json .load (f )
44+ if data .get ("username" ):
45+ self ._username = data ["username" ]
46+ # 标记为需要重新验证
47+ logger .info (f"发现已保存的登录信息: { self ._username } " )
48+ except Exception as e :
49+ logger .debug (f"读取 cookies 文件失败: { e } " )
50+
51+ def _save_session (self ) -> None :
52+ """保存登录会话到文件"""
53+ if not self ._logged_in or not self ._username :
54+ return
55+
56+ cookies_file = self .config .cookies_file
57+ try :
58+ data = {
59+ "username" : self ._username ,
60+ "logged_in" : True ,
61+ }
62+ with open (cookies_file , "w" , encoding = "utf-8" ) as f :
63+ json .dump (data , f , ensure_ascii = False , indent = 2 )
64+ logger .debug (f"登录信息已保存到: { cookies_file } " )
65+ except Exception as e :
66+ logger .error (f"保存登录信息失败: { e } " )
67+
68+ def _clear_session (self ) -> None :
69+ """清除保存的登录会话"""
70+ cookies_file = self .config .cookies_file
71+ if cookies_file .exists ():
72+ try :
73+ cookies_file .unlink ()
74+ logger .debug ("已清除保存的登录信息" )
75+ except Exception as e :
76+ logger .error (f"清除登录信息失败: { e } " )
77+
3278 @property
3379 def is_logged_in (self ) -> bool :
3480 """检查是否已登录"""
@@ -81,6 +127,9 @@ def _login_sync(self, username: str, password: str) -> tuple[bool, str]:
81127 self ._username = username
82128 self ._client = client
83129
130+ # 持久化保存
131+ self ._save_session ()
132+
84133 logger .info (f"用户 { username } 登录成功" )
85134 return True , f"登录成功,欢迎 { username } !"
86135
@@ -96,6 +145,37 @@ def _login_sync(self, username: str, password: str) -> tuple[bool, str]:
96145
97146 return False , f"登录失败: { error_msg } "
98147
148+ async def auto_login (self ) -> tuple [bool , str ]:
149+ """
150+ 使用配置的凭据自动登录
151+
152+ Returns:
153+ (成功与否, 消息)
154+ """
155+ if not self .config .has_credentials ():
156+ return False , "未配置登录凭据"
157+
158+ if self ._logged_in :
159+ return True , f"已登录: { self ._username } "
160+
161+ return await self .login (self .config .jm_username , self .config .jm_password )
162+
163+ async def ensure_logged_in (self ) -> tuple [bool , str ]:
164+ """
165+ 确保已登录(如果未登录则尝试自动登录)
166+
167+ Returns:
168+ (成功与否, 消息)
169+ """
170+ if self ._logged_in :
171+ return True , f"已登录: { self ._username } "
172+
173+ # 尝试使用配置的凭据自动登录
174+ if self .config .has_credentials ():
175+ return await self .auto_login ()
176+
177+ return False , "未登录,请使用 /jmlogin 登录"
178+
99179 def logout (self ) -> tuple [bool , str ]:
100180 """
101181 登出
@@ -111,6 +191,9 @@ def logout(self) -> tuple[bool, str]:
111191 self ._username = None
112192 self ._client = None
113193
194+ # 清除保存的会话
195+ self ._clear_session ()
196+
114197 logger .info (f"用户 { username } 已登出" )
115198 return True , f"已登出账号 { username } "
116199
@@ -124,4 +207,5 @@ def get_login_status(self) -> dict:
124207 return {
125208 "logged_in" : self ._logged_in ,
126209 "username" : self ._username ,
210+ "has_credentials" : self .config .has_credentials (),
127211 }
0 commit comments