fix: WebSocket 鉴权 — Cookie 优先 (支持 HttpOnly)
根因: panel_token 是 HttpOnly cookie, JS getCookie() 读不到 → 前端 WS ?token= 参数为空 → 认证失败 → 仪表盘无数据 修复: - _ws_auth_wrapper: Cookie 优先 → query token 备用 → API Key - 浏览器同源 WS 自动发送 Cookie, 无需 ?token= - dashboard.js / logs.js 移除多余的 getCookie+?token= Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,56 @@
|
|||||||
|
framework:
|
||||||
|
debug: true
|
||||||
|
name: SenSu
|
||||||
|
version: v0.6.0
|
||||||
|
logging:
|
||||||
|
debug_level_file: true
|
||||||
|
level: DEBUG
|
||||||
|
max_file_size: 10MB
|
||||||
|
max_log_files: 20
|
||||||
|
plugins:
|
||||||
|
auto_load: true
|
||||||
|
hot_reload: true
|
||||||
|
max_retry_count: 3
|
||||||
|
isolation: true
|
||||||
|
# 自动启动脚本 — 框架启动时后台拉起
|
||||||
|
auto_start_scripts:
|
||||||
|
enabled: true
|
||||||
|
scripts: []
|
||||||
|
# 示例:
|
||||||
|
# - name: cyrene_debug
|
||||||
|
# path: ~/cyrene_debug_server.py
|
||||||
|
# enabled: true
|
||||||
|
# args: []
|
||||||
|
# cwd: ~
|
||||||
|
# TUI配置
|
||||||
|
tui:
|
||||||
|
enabled: true
|
||||||
|
refresh_rate: 30
|
||||||
|
# TUI布局配置
|
||||||
|
layout:
|
||||||
|
grid_rows: "4fr 5fr 1fr" # 三行布局:日志区域、消息区域、输入区域的比例
|
||||||
|
# TUI样式配置
|
||||||
|
styles:
|
||||||
|
log_area: "border: solid green; overflow-y: auto;"
|
||||||
|
message_area: "border: solid yellow; overflow-y: auto;"
|
||||||
|
input_area: "border: solid red;"
|
||||||
|
# TUI日志显示配置
|
||||||
|
log_display:
|
||||||
|
max_lines: 200
|
||||||
|
# 互联网服务配置
|
||||||
|
internet:
|
||||||
|
websocket:
|
||||||
|
host: "0.0.0.0"
|
||||||
|
port: 4240
|
||||||
|
# 其他websocket配置...
|
||||||
|
http:
|
||||||
|
host: "0.0.0.0"
|
||||||
|
port: 4200
|
||||||
|
# 其他http配置...
|
||||||
|
panel:
|
||||||
|
entrance:
|
||||||
|
path: "/SenSu"
|
||||||
|
username: "admin"
|
||||||
|
password: "admin"
|
||||||
|
|
||||||
|
|
||||||
@@ -42,5 +42,16 @@
|
|||||||
"framework.command.execute"
|
"framework.command.execute"
|
||||||
],
|
],
|
||||||
"timestamp": 17177.106703342
|
"timestamp": 17177.106703342
|
||||||
|
},
|
||||||
|
"fe262a42": {
|
||||||
|
"plugin_name": "sentinel",
|
||||||
|
"permissions": [
|
||||||
|
"plugin.sentinel.read",
|
||||||
|
"plugin.sentinel.write",
|
||||||
|
"plugin.network.access",
|
||||||
|
"framework.event.subscribe",
|
||||||
|
"framework.command.execute"
|
||||||
|
],
|
||||||
|
"timestamp": 25770.11842246
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -93,7 +93,7 @@ commands:
|
|||||||
permissions:
|
permissions:
|
||||||
- framework.command.test
|
- framework.command.test
|
||||||
source: internal
|
source: internal
|
||||||
last_updated: 17177.060053342
|
last_updated: 25770.099665272
|
||||||
plugin_commands:
|
plugin_commands:
|
||||||
sentinel:
|
sentinel:
|
||||||
sentinel: *id001
|
sentinel: *id001
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
http_port: 4200
|
http_port: 4200
|
||||||
last_updated: 17177.1104973
|
last_updated: 25770.118859595
|
||||||
plugin_routes:
|
plugin_routes:
|
||||||
sentinel:
|
sentinel:
|
||||||
- methods:
|
- methods:
|
||||||
|
|||||||
@@ -13,11 +13,21 @@ logger = logging.getLogger(__name__)
|
|||||||
_sys_ws_clients: set = set()
|
_sys_ws_clients: set = set()
|
||||||
|
|
||||||
def _ws_auth_wrapper(handler):
|
def _ws_auth_wrapper(handler):
|
||||||
"""WebSocket 鉴权包装 — 从 query string 取 token 验证"""
|
"""WebSocket 鉴权 — Cookie 优先(同源自动发送), query token 备用"""
|
||||||
async def wrapper(request):
|
async def wrapper(request):
|
||||||
token = request.query.get("token", "")
|
# 1. Cookie (浏览器同源自动发送, 支持 HttpOnly)
|
||||||
|
token = request.cookies.get("panel_token", "")
|
||||||
|
# 2. Query string token 备用 (跨域/非浏览器客户端)
|
||||||
|
if not token:
|
||||||
|
token = request.query.get("token", "")
|
||||||
|
# 3. API Key 验证
|
||||||
session_store = request.app.get("panel_session_store", {})
|
session_store = request.app.get("panel_session_store", {})
|
||||||
if not token or token not in session_store:
|
is_valid = token and token in session_store
|
||||||
|
if not is_valid and token:
|
||||||
|
from services.web_panel.routes.apikeys import validate_api_key
|
||||||
|
is_valid = validate_api_key(token) is not None
|
||||||
|
|
||||||
|
if not is_valid:
|
||||||
ws = web.WebSocketResponse()
|
ws = web.WebSocketResponse()
|
||||||
await ws.prepare(request)
|
await ws.prepare(request)
|
||||||
await ws.send_str(json.dumps({"error": "Unauthorized"}))
|
await ws.send_str(json.dumps({"error": "Unauthorized"}))
|
||||||
|
|||||||
@@ -32,8 +32,7 @@ window.DashboardModule = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var base = window.location.pathname.split("/").slice(0, 2).join("/");
|
var base = window.location.pathname.split("/").slice(0, 2).join("/");
|
||||||
var tok = getCookie("panel_token");
|
var ws = new WebSocket("ws://" + location.host + base + "/api/system/ws");
|
||||||
var ws = new WebSocket("ws://" + location.host + base + "/api/system/ws?token=" + (tok || ""));
|
|
||||||
self.ws = ws;
|
self.ws = ws;
|
||||||
|
|
||||||
ws.onopen = function() {
|
ws.onopen = function() {
|
||||||
|
|||||||
@@ -25,8 +25,7 @@ window.LogsModule = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var base = window.location.pathname.split("/").slice(0, 2).join("/");
|
var base = window.location.pathname.split("/").slice(0, 2).join("/");
|
||||||
var tok = getCookie("panel_token");
|
var ws = new WebSocket("ws://" + location.host + base + "/api/logs/ws");
|
||||||
var ws = new WebSocket("ws://" + location.host + base + "/api/logs/ws?token=" + (tok || ""));
|
|
||||||
self.ws = ws;
|
self.ws = ws;
|
||||||
|
|
||||||
ws.onopen = function() {
|
ws.onopen = function() {
|
||||||
|
|||||||
Reference in New Issue
Block a user