feat(security): JWT 改 HttpOnly Cookie + P2 死依赖清理 + Dockerfile pnpm 化

- #2 JWT HttpOnly Cookie: authSlice/LoginModalContext 不再向 localStorage
  写入 access/refresh/token_type (仅存非敏感 user), 登出/401 时调用
  POST /user/logout/ 清服务端 Cookie; axios withCredentials=true,
  401 无 token 也走 /user/token/refresh/ 空载荷刷新(单飞); WS createWebSocket
  token 参数可省略由 Cookie 鉴权; Navbar/MobileTopNav/Chat/ChatMobile/Bug/
  useRecordHistory 的 localStorage access_token 判断改走登录态
- P2 #10 死依赖清理: 移除 @chakra-ui/react @emotion/react next-themes
  zustand react-lorem-ipsum react-syntax-highlighter qrcode.react
  @types/qrcode; 删 components/ui 整目录与 Markdown/Markdown.tsx;
  删 package-lock.json yarn.lock 仅留 pnpm-lock; untrack tsconfig.tsbuildinfo
- Dockerfile: 弃用 npm install, 改 corepack pnpm@9 --frozen-lockfile
- nginx.conf: API 白名单补 air-quality/weather/currency/shorturl,
  补 /swagger.json 反代
This commit is contained in:
2026-09-08 11:28:26 +08:00
parent 8ad3abadfc
commit 26feb3d277
28 changed files with 319 additions and 13841 deletions
+29 -7
View File
@@ -10,9 +10,9 @@ server {
gzip_min_length 1024;
gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml+rss application/javascript application/json;
# WebSocket 反代(聊天等实时功能)
# WebSocket 反代(聊天 ws/chat、扫码登录 ws/qr-status → Granian + Channels)
location /ws/ {
proxy_pass http://127.0.0.1:8000;
proxy_pass http://backend:8000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
@@ -24,9 +24,10 @@ server {
proxy_send_timeout 3600s;
}
# API 反代(路由分散在 /api /user /bug /article /chat /learn /message /tool /history /media 等前缀下)
location ~ ^/(api|user|bug|article|chat|learn|message|tool|history|media|search|app|logs|s)/ {
proxy_pass http://127.0.0.1:8000;
# API 反代 → Granian(ADRF 异步视图)
# 路由分散在 /api /user /bug /article /chat /learn /message /tool /history /media 等前缀下
location ~ ^/(api|user|bug|article|chat|learn|message|tool|history|media|search|app|logs|s|air-quality|weather|currency|shorturl)/ {
proxy_pass http://backend:8000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
@@ -38,10 +39,31 @@ server {
client_max_body_size 50M;
}
# 静态资源缓存(图片/字体/JS/CSS)
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
# Django admin / swagger / redoc / i18n / 测试页
location /admin/ { proxy_pass http://backend:8000; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; client_max_body_size 50M; }
location /swagger { proxy_pass http://backend:8000; proxy_set_header Host $host; }
location /swagger.json { proxy_pass http://backend:8000; proxy_set_header Host $host; }
location /redoc/ { proxy_pass http://backend:8000; proxy_set_header Host $host; }
location /i18n/ { proxy_pass http://backend:8000; proxy_set_header Host $host; }
location /test/ { proxy_pass http://backend:8000; proxy_set_header Host $host; }
# 带哈希指纹的构建产物:永久强缓存(immutable)
location ~* \assets/.*\.(js|css|png|jpg|jpeg|gif|webp|avif|ico|svg|woff|woff2|ttf|eot)$ {
expires 1y;
add_header Cache-Control "public, immutable";
access_log off;
}
# 其他静态资源(public/ 目录:图片/字体等无指纹文件):适中缓存
location ~* \.(png|jpg|jpeg|gif|webp|ico|svg|woff|woff2|ttf|eot)$ {
expires 7d;
add_header Cache-Control "public";
access_log off;
}
# index.html 不缓存,保证发版后立即生效
location = /index.html {
add_header Cache-Control "no-cache, no-store, must-revalidate";
}
# SPA 路由回退(放在最后,避免拦截上面的 API 请求)