wangzhibo
2026-05-09 53418655c061ac26f66058253f39200aced1ab1d
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# ---------------------------------------------------------------------------
# upstream board_app(默认 127.0.0.1:3000)后端可以是以下任一实现,无需改本 conf:
#   - Node:npm run start(Express,见 src/app.ts + src/routes/boardRouter.ts)
#   - ASP.NET:Kestrel 监听 3000(见 aspnet/BoardApp,PathBase=/board)
# 二者须满足的 HTTP 契约(供 auth_request 与浏览器同源 Cookie):
#   - GET /board/check/ 已登录 → 200;未登录 → 401(纯文本即可)
#   - Session Cookie 名 board.sid,Path=/,与 80 入口同主机以便 nginx 子请求带 Cookie
#   - /board/login、POST /board/api/login、/board/static/… 等由应用自身处理
# 配置目录:两套程序均读同一套 config/*.json(或通过 BOARD_CONFIG_DIR 指向同一目录)。
# ---------------------------------------------------------------------------
# 访问模型(80 端口统一入口)
# 1) 任意 URL 若匹配 /board/… → 直接反代到 Board(本机 board_app),不经过 auth_request,
#    避免登录页、/api/login、/board/check/ 等与鉴权子请求死循环。
# 2) 其余所有路径 → 先 auth_request 调用内部 /internal/board_check(实质请求 Board 的
#    GET /board/check/ 且透传 Cookie)。子请求返回 2xx 视为已登录,再 proxy_pass 到 DataEase。
#    子请求 401/403 → error_page 跳转到 /board/login?next=原 URI。
# 3) 注意:nginx 的「rewrite 到 8100」在这里通过 proxy_pass 实现(HTTP 反代),不是 rewrite 指令。
# ---------------------------------------------------------------------------
 
upstream board_app {
    server 127.0.0.1:3000;
}
 
upstream dataease_upstream {
    server 127.0.0.1:8100;
}
 
server {
    listen 80;
    server_name 192.168.0.235; # 建议明确写出 IP 或域名
 
    # 0) /board 无尾斜杠时,^~ /board/ 不会匹配,会误入 location / 被反代到 DataEase,必须显式纠正
    location = /board {
        return 302 $scheme://$http_host/board/;
    }
 
    # 1) 门户应用自身的路径(优先级最高)
    # 确保 /board/ 及其子路径(登录页、API、静态资源)绝不走鉴权,否则会死循环
    location ^~ /board/ {
        proxy_pass http://board_app;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
 
    # 2) 内部鉴权接口(仅由 auth_request 发起,外部无法直接访问)
    location = /internal/board_check {
        internal;
        proxy_pass http://board_app/board/check/;
        proxy_pass_request_body off;
        proxy_set_header Content-Length "";
        proxy_set_header Host $host;
        proxy_set_header X-Original-URI $request_uri;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        # 必须透传 Cookie,否则 Board 无法根据 session 判断已登录
        proxy_set_header Cookie $http_cookie;
    }
 
    # 3) 核心控制:除 /board、/board/… 以外的所有请求 — 先鉴权,再反代 DataEase:8100
    location / {
        auth_request /internal/board_check;
 
        # 鉴权子请求失败:跳转门户登录页(带 next 回跳)
        error_page 401 = @board_need_login;
        error_page 403 = @board_need_login;
 
        # 已登录:反代到 DataEase(等价于「非 board 流量进 8100」)
        proxy_pass http://dataease_upstream;
        
        # --- 关键修改:拦截 DataEase 自身的登录重定向 ---
        # 如果 DataEase 试图把用户甩到它自己的 /login,Nginx 强制拦截并改写
        proxy_intercept_errors on; 
        
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        
        # 防止 DataEase 返回的 Location Header 暴露 8100 端口
        proxy_redirect http://127.0.0.1:8100/ /;
    }
 
    # 4) 统一登录跳转逻辑
    location @board_need_login {
        # $request_uri 包含了原始请求路径,登录后可跳回
        return 302 $scheme://$http_host/board/login?next=$request_uri;
    }
}