feat: 统一JWT密钥配置并修复签名验证问题

修复前端签名生成中bodyString硬编码问题
添加start-frontend.sh脚本启动前端服务
统一manage-app和gateway的JWT密钥配置
修复Repository扫描路径问题
更新测试配置和依赖
重构表名映射为sys_user和sys_role
完善用户实体类字段映射
添加集成测试配置和测试用例
This commit is contained in:
张翔
2026-04-02 12:28:49 +08:00
parent 6392c08560
commit b0f91d74f5
63 changed files with 3287 additions and 889 deletions
@@ -0,0 +1,125 @@
"""
检查前端实际发送的签名头
"""
from playwright.sync_api import sync_playwright
import time
def check_frontend_signature():
"""检查前端签名头"""
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
context = browser.new_context()
page = context.new_page()
signature_headers = {}
def handle_request(request):
if '/api/users/page' in request.url:
signature_headers['url'] = request.url
signature_headers['method'] = request.method
signature_headers['X-Signature'] = request.headers.get('X-Signature', 'None')
signature_headers['X-Timestamp'] = request.headers.get('X-Timestamp', 'None')
signature_headers['X-Nonce'] = request.headers.get('X-Nonce', 'None')
print(f"\n捕获到用户列表请求:")
print(f" URL: {request.url}")
print(f" Method: {request.method}")
print(f" X-Signature: {signature_headers['X-Signature'][:30] if signature_headers['X-Signature'] != 'None' else 'None'}...")
print(f" X-Timestamp: {signature_headers['X-Timestamp']}")
print(f" X-Nonce: {signature_headers['X-Nonce']}")
page.on('request', handle_request)
try:
print("=" * 60)
print("检查前端签名头")
print("=" * 60)
print("\n1. 登录...")
page.goto('http://localhost:3002/login')
page.wait_for_load_state('networkidle')
page.fill('input[type="text"], input[placeholder*="用户名"]', 'admin')
page.fill('input[type="password"]', 'admin123')
with page.expect_navigation(timeout=10000):
page.click('button:has-text("登录")')
time.sleep(2)
print("\n2. 访问用户管理页面...")
page.goto('http://localhost:3002/users')
time.sleep(5)
page.wait_for_load_state('networkidle')
if signature_headers:
print("\n" + "=" * 60)
print("前端签名头信息:")
print("=" * 60)
url = signature_headers.get('url', '')
method = signature_headers.get('method', 'GET')
signature = signature_headers.get('X-Signature', 'None')
timestamp = signature_headers.get('X-Timestamp', 'None')
nonce = signature_headers.get('X-Nonce', 'None')
print(f"URL: {url}")
print(f"Method: {method}")
print(f"X-Signature: {signature}")
print(f"X-Timestamp: {timestamp}")
print(f"X-Nonce: {nonce}")
# 手动验证签名
if timestamp != 'None' and nonce != 'None':
from urllib.parse import urlparse, parse_qs
parsed = urlparse(url)
path = parsed.path
query = parsed.query
print(f"\n路径: {path}")
print(f"查询参数: {query}")
# 生成期望的签名
import hmac
import hashlib
import base64
secret = 'NovalonManageSystemSecretKey2026'
string_to_sign = '\n'.join([
method,
path,
query or '',
'',
timestamp,
nonce
])
expected_signature = base64.b64encode(
hmac.new(
secret.encode('utf-8'),
string_to_sign.encode('utf-8'),
hashlib.sha256
).digest()
).decode('utf-8')
print(f"\n期望的签名: {expected_signature}")
print(f"实际的签名: {signature}")
if signature == expected_signature:
print("\n✅ 签名匹配")
else:
print("\n❌ 签名不匹配")
print(f"\n签名字符串:\n{string_to_sign}")
else:
print("\n❌ 未捕获到用户列表请求")
except Exception as e:
print(f"\n❌ 错误: {str(e)}")
import traceback
traceback.print_exc()
finally:
browser.close()
if __name__ == "__main__":
check_frontend_signature()