Skip to content

Commit b503806

Browse files
committed
feat(auth): implement login with session persistence
- Add /jmlogin, /jmlogout, /jmstatus commands - Save login state to cookies.json for persistence - Support auto-login via config credentials - Add core/auth.py with JMAuthManager class
1 parent e8f180f commit b503806

5 files changed

Lines changed: 131 additions & 4 deletions

File tree

CHANGELOG.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,27 @@
22

33
所有版本更新记录。
44

5+
## **v2.2.0** (2025-12-27)
6+
7+
### 新增功能
8+
- **登录功能** - 新增账号登录相关命令
9+
- `/jmlogin <用户名> <密码>` - 登录JM账号
10+
- `/jmlogout` - 登出账号
11+
- `/jmstatus` - 查看登录状态
12+
- 支持在配置中保存凭据,实现自动登录
13+
- 登录状态持久化保存,重启后自动恢复
14+
15+
### 新增配置项
16+
- `jm_username` - JM账号用户名(可选)
17+
- `jm_password` - JM账号密码(可选)
18+
19+
### 架构优化
20+
- 新增 `core/auth.py` - 认证管理器 `JMAuthManager`
21+
- 支持 cookies 文件持久化存储
22+
- 自动登录和登录状态恢复机制
23+
24+
---
25+
526
## **v2.1.1** (2025-12-27)
627

728
### 架构优化

README.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
<br>
1212
<div align="center">
13-
<a href="#更新日志"><img src="https://img.shields.io/badge/VERSION-v2.1.1-E91E63?style=for-the-badge" alt="Version"></a>
13+
<a href="#更新日志"><img src="https://img.shields.io/badge/VERSION-v2.2.0-E91E63?style=for-the-badge" alt="Version"></a>
1414
<a href="https://github.com/GEMILUXVII/astrbot_plugin_jm_cosmos/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-AGPL--3.0-009688?style=for-the-badge" alt="License"></a>
1515
<a href="https://www.python.org/"><img src="https://img.shields.io/badge/PYTHON-3.10+-3776AB?style=for-the-badge&logo=python&logoColor=white" alt="Python"></a>
1616
<a href="https://github.com/AstrBotDevs/AstrBot"><img src="https://img.shields.io/badge/AstrBot-Compatible-00BFA5?style=for-the-badge&logo=robot&logoColor=white" alt="AstrBot Compatible"></a>
@@ -95,6 +95,9 @@ pip install -r requirements.txt
9595
| `/jms <关键词>` | 搜索漫画 | `/jms 标签名` |
9696
| `/jmi <ID>` | 查看本子详情 | `/jmi 123456` |
9797
| `/jmrank` | 查看排行榜 | `/jmrank week 1` |
98+
| `/jmlogin` | 登录JM账号 | `/jmlogin u p` |
99+
| `/jmlogout` | 登出账号 | `/jmlogout` |
100+
| `/jmstatus` | 查看登录状态 | `/jmstatus` |
98101
| `/jmhelp` | 查看帮助信息 | `/jmhelp` |
99102

100103
## 配置说明
@@ -167,7 +170,7 @@ proxy_url: http://127.0.0.1:7890
167170

168171
查看完整更新日志:[CHANGELOG.md](./CHANGELOG.md)
169172

170-
**当前版本:v2.1.1** - 优化目录结构
173+
**当前版本:v2.2.0** - 新增登录功能
171174

172175
## 注意事项
173176

core/auth.py

Lines changed: 85 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
"""
22
JMComic 认证管理模块
33
4-
提供登录、登出、会话管理等认证功能。
4+
提供登录、登出、会话管理等认证功能,支持 cookies 持久化
55
"""
66

7+
import json
8+
79
from astrbot.api import logger
810

911
from .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
}

core/base/config.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,25 @@ def debug_mode(self) -> bool:
120120
"""调试模式"""
121121
return self.plugin_config.get("debug_mode", False)
122122

123+
@property
124+
def jm_username(self) -> str:
125+
"""JM账号用户名"""
126+
return self.plugin_config.get("jm_username", "")
127+
128+
@property
129+
def jm_password(self) -> str:
130+
"""JM账号密码"""
131+
return self.plugin_config.get("jm_password", "")
132+
133+
@property
134+
def cookies_file(self) -> Path:
135+
"""Cookies文件路径"""
136+
return self.data_dir / "cookies.json"
137+
138+
def has_credentials(self) -> bool:
139+
"""检查是否配置了登录凭据"""
140+
return bool(self.jm_username and self.jm_password)
141+
123142
def is_admin(self, user_id: str) -> bool:
124143
"""检查用户是否是管理员"""
125144
if not self.admin_only:

metadata.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: jm_cosmos2
22
desc: JM漫画下载插件 - 支持搜索、下载禁漫天堂的漫画本子,基于jmcomic库,支持加密PDF/ZIP打包
3-
version: v2.1.1
3+
version: v2.2.0
44
author: GEMILUXVII
55
repo: https://github.com/GEMILUXVII/astrbot_plugin_jm_cosmos

0 commit comments

Comments
 (0)