使用 docker 和 nginx 在 localhost 中调试第三方身份验证

Posted

技术标签:

【中文标题】使用 docker 和 nginx 在 localhost 中调试第三方身份验证【英文标题】:Debug third-party authentications in localhost with docker and nginx 【发布时间】:2021-12-15 18:35:11 【问题描述】:

我们有一个网站,我们刚刚在其中添加了第三方身份验证,例如 Google、Twitter。我正在尝试在 localhost (MacOS) 中测试这些身份验证。

我正在运行一个docker来运行nginx,这里是docker-compose-dev.xml

version: "3"
services:
  https:
    image: bitnami/nginx:latest
    restart: unless-stopped
    ports:
      - 443:443/tcp
    volumes:
      - ./conf.d/dev.conf:/opt/bitnami/nginx/conf/server_blocks/default.conf:ro
    extra_hosts:
      - "host.docker.internal:host-gateway"

这里是conf.d/dev.conf

upstream funfun 
   server 178.62.87.72:443;

server 
    listen  443 ssl;
    server_name localhost;
    ssl_certificate /certs/server.crt;
    ssl_certificate_key /certs/server.key;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;
    ssl_session_timeout 1d;
    ssl_stapling off;
    ssl_stapling_verify off;
    add_header Strict-Transport-Security max-age=15768000;
    add_header X-Frame-Options "";
    proxy_ssl_name "www.funfun.io";
    proxy_ssl_server_name on;
    location ~ /socialLoginSuccess 
        rewrite ^ '/#/socialLoginSuccess' redirect;
     
    location ~ /auth/(.*) 
        proxy_pass  https://funfun/10studio/auth/$1?$query_string;
        proxy_set_header Host localhost;
     
    location / 
        proxy_set_header    Host                $host;
        proxy_set_header    X-Forwarded-For     $proxy_add_x_forwarded_for;
        proxy_set_header    X-Forwarded-Proto   $scheme;
        proxy_set_header    Accept-Encoding     "";
        proxy_set_header    Proxy               "";
        proxy_pass          http://host.docker.internal:3000/;
        # These three lines added as per https://github.com/socketio/socket.io/issues/1942 to remove socketio error
        proxy_http_version 1.1;
        proxy_set_header   Upgrade $http_upgrade;
        proxy_set_header   Connection "upgrade";
    

我们启动应用程序的方式是sudo PORT=8000 HTTPS=true ./node_modules/.bin/react-scripts start。然后浏览器中的https://localhost:8000/#/sign 确实会打开身份验证按钮所在的页面。

链接到 Google 身份验证的按钮的 url 是https://localhost/10studio/auth/google。点击后,在浏览器地址栏先看到https://localhost/10studio/auth/google,但是没有出现输入谷歌ID和密码的页面,几秒后,url变成https://localhost/#/socialLoginSuccess,页面显示502 Bad Gateway。我在运行 nginx 的终端中看到以下日志:

$ docker-compose --f docker-compose-dev.yml up
WARNING: Found orphan containers (frontend_10studio_1, frontend_frontend_1) for this project. If you removed or renamed this service in your compose file, you can run this command with the --remove-orphans flag to clean it up.
Starting frontend_https_1 ... done
Attaching to frontend_https_1
https_1  | nginx 21:24:05.37 
https_1  | nginx 21:24:05.38 Welcome to the Bitnami nginx container
https_1  | nginx 21:24:05.38 Subscribe to project updates by watching https://github.com/bitnami/bitnami-docker-nginx
https_1  | nginx 21:24:05.39 Submit issues and feature requests at https://github.com/bitnami/bitnami-docker-nginx/issues
https_1  | nginx 21:24:05.39 
https_1  | nginx 21:24:05.39 INFO  ==> ** Starting NGINX setup **
https_1  | nginx 21:24:05.42 INFO  ==> Validating settings in NGINX_* env vars
https_1  | nginx 21:24:05.43 INFO  ==> Initializing NGINX
https_1  | realpath: /bitnami/nginx/conf/vhosts: No such file or directory
https_1  | 
https_1  | nginx 21:24:05.45 INFO  ==> ** NGINX setup finished! **
https_1  | nginx 21:24:05.47 INFO  ==> ** Starting NGINX **
https_1  | 172.19.0.1 - - [08/Nov/2021:21:25:06 +0000] "GET /10studio/auth/google HTTP/1.1" 302  0 "https://localhost:8000/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (Khtml, like Gecko) Chrome/95.0.4638.54 Safari/537.36" "-"
https_1  | 172.19.0.1 - - [08/Nov/2021:21:25:07 +0000] "GET /auth/google/callback?code=4%2F0AX4XfWiqleRl2StBpNOgOtzjqZlftvq9-uDmiPVLZqcgo2xjjhohu47iAV5qxoJThaQYzg&scope=email+profile+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email+openid&authuser=0&prompt=none HTTP/1.1" 302  82 "https://localhost:8000/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 Safari/537.36" "-"
https_1  | 172.19.0.1 - - [08/Nov/2021:21:25:07 +0000] "GET /auth/signinSuccess HTTP/1.1" 302  82 "https://localhost:8000/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 Safari/537.36" "-"
https_1  | 172.19.0.1 - - [08/Nov/2021:21:25:07 +0000] "GET /socialLoginSuccess HTTP/1.1" 302  138 "https://localhost:8000/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 Safari/537.36" "-"
https_1  | 2021/11/08 21:25:39 [error] 27#27: *2 connect() failed (110: Connection timed out) while connecting to upstream, client: 172.19.0.1, server: localhost, request: "GET / HTTP/1.1", upstream: "http://192.168.65.1:3000/", host: "localhost", referrer: "https://localhost:8000/"
https_1  | 172.19.0.1 - - [08/Nov/2021:21:25:39 +0000] "GET / HTTP/1.1" 502  552 "https://localhost:8000/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 Safari/537.36" "-"

有人知道这里出了什么问题吗?

另外,当我调试 nginx 时,它对我来说就像一个黑匣子。我真的希望能够跟踪并查看哪个 url 进入哪个位置块,并更改为哪个 url(通过proxy_passrewrite 等)。有没有人有更好的方法来调试或记录它?

编辑 1:

我还尝试了另一个稍微不同的docker-compose-dev.xml

version: "3"
services:
  https:
    image: bitnami/nginx:latest
    restart: unless-stopped
    ports:
      - 443:443/tcp
    volumes:
      - ./conf.d/dev.mac.conf:/opt/bitnami/nginx/conf/server_blocks/default.conf:ro
    extra_hosts:
      - "172.17.0.1:host-gateway"

dev.mac.conf略有不同:

upstream funfun 
   server 178.62.87.72:443;

server 
    listen 443 ssl;
    server_name localhost;
    ssl_certificate /certs/server.crt;
    ssl_certificate_key /certs/server.key;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;
    ssl_session_timeout 1d;
    ssl_stapling off;
    ssl_stapling_verify off;
    add_header Strict-Transport-Security max-age=15768000;
    add_header X-Frame-Options "";
    proxy_ssl_name "www.funfun.io";
    proxy_ssl_server_name on;
    location ~ /socialLoginSuccess 
        rewrite ^ '/#/socialLoginSuccess' redirect;
     
    location ~ /auth/(.*) 
        proxy_pass  https://funfun/10studio/auth/$1?$query_string;
        proxy_set_header Host localhost;
     
    location / 
        proxy_set_header    Host                $host;
        proxy_set_header    X-Forwarded-For     $proxy_add_x_forwarded_for;
        proxy_set_header    X-Forwarded-Proto   $scheme;
        proxy_set_header    Accept-Encoding     "";
        proxy_set_header    Proxy               "";
        proxy_pass          http://172.17.0.1:8000/;

        # These three lines added as per https://github.com/socketio/socket.io/issues/1942 to remove socketio error
        proxy_http_version 1.1;
        proxy_set_header   Upgrade $http_upgrade;
        proxy_set_header   Connection "upgrade";
    

我仍然通过sudo PORT=8000 HTTPS=true ./node_modules/.bin/react-scripts start 启动应用程序。这一次,https://localhost:8000/#/sign 在浏览器中打开了认证按钮所在的页面。单击链接到https://localhost/10studio/auth/google 的按钮将打开 Google 身份验证页面。认证成功后,url变为https://localhost/#/socialLoginSuccess,页面显示502 Bad Gateway。但是,正确的 url 应该是 https://localhost:8000/#/socialLoginSuccess

这是日志:

https_1  | nginx 03:12:10.32 INFO  ==> ** Starting NGINX **
https_1  | 172.19.0.1 - - [12/Nov/2021:03:12:28 +0000] "GET /10studio/auth/google HTTP/1.1" 302  0 "https://localhost:8000/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:94.0) Gecko/20100101 Firefox/94.0" "-"
https_1  | 172.19.0.1 - - [12/Nov/2021:03:12:46 +0000] "GET /auth/google/callback?code=4%2F0AX4XfWgQ8g3LC6nYxBbk-BjBq0cWGFcfSwoPWZbC8Rky0IVngpAtKTTuYIbYsgbW96g6Dg&scope=email+profile+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email+openid&authuser=0&prompt=consent HTTP/1.1" 302  82 "https://accounts.google.fr/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:94.0) Gecko/20100101 Firefox/94.0" "-"
https_1  | 172.19.0.1 - - [12/Nov/2021:03:12:46 +0000] "GET /auth/signinSuccess HTTP/1.1" 302  82 "https://accounts.google.fr/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:94.0) Gecko/20100101 Firefox/94.0" "-"
https_1  | 172.19.0.1 - - [12/Nov/2021:03:12:46 +0000] "GET /socialLoginSuccess HTTP/1.1" 302  138 "https://accounts.google.fr/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:94.0) Gecko/20100101 Firefox/94.0" "-"
https_1  | 172.19.0.1 - - [12/Nov/2021:03:12:46 +0000] "GET / HTTP/1.1" 502  150 "https://accounts.google.fr/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:94.0) Gecko/20100101 Firefox/94.0" "-"
https_1  | 2021/11/12 03:12:46 [error] 28#28: *1 connect() failed (111: Connection refused) while connecting to upstream, client: 172.19.0.1, server: localhost, request: "GET / HTTP/1.1", upstream: "http://172.17.0.1:8000/", host: "localhost", referrer: "https://accounts.google.fr/"
https_1  | 172.19.0.1 - - [12/Nov/2021:03:12:46 +0000] "GET /favicon.ico HTTP/1.1" 502  150 "https://localhost/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:94.0) Gecko/20100101 Firefox/94.0" "-"
https_1  | 2021/11/12 03:12:46 [error] 28#28: *1 connect() failed (111: Connection refused) while connecting to upstream, client: 172.19.0.1, server: localhost, request: "GET /favicon.ico HTTP/1.1", upstream: "http://172.17.0.1:8000/favicon.ico", host: "localhost", referrer: "https://localhost/"

我相信这个版本的配置文件更接近正确的解决方案。唯一的问题是最终的 url 应该是 https://localhost:8000/#/socialLoginSuccess 而不是 https://localhost/#/socialLoginSuccess。有谁知道如何做到这一点?

【问题讨论】:

【参考方案1】:

您在日志中有错误(这不是身份验证的问题):

[error] 27#27: *2 connect() failed (110: Connection timed out) while connecting to upstream, client: 172.19.0.1, server: localhost, request: "GET / HTTP/1.1", upstream: "http://192.168.65.1:3000/"

您的 nginx 容器无法访问已配置的上游 (http://host.docker.internal:3000/)。导致该错误的原因有很多:错误的网络/端口配置、端口暴露、moby itself may have a own bugs with host.docker.internal DNS configuration、...

【讨论】:

【参考方案2】:

OAUTH 流程成功发生。 请注意,大部分流程都发生在 localhost:8000 上,这意味着绕过 nginx 并直接访问您的应用程序。 您的应用程序在端口 8000 上运行,但您已将 nginx 配置为连接到端口 3000 上的“上游”(您的应用程序)(请参阅您的 nginx 配置)。

在流程结束时,请求不再直接发送到您的应用程序,而是转到 nginx,然后尝试连接到端口 3000 上的应用程序/上游,这不起作用,因为您的应用程序在 8000 上运行。

更新您的 nginx 配置以指向端口 8000,然后重试。

我还建议您测试连接到 nginx 的整个流程,而不是直接连接到端口 8000 上的应用,以减少混淆。

https_1  | 172.19.0.1 - - [08/Nov/2021:21:25:07 +0000] "GET /socialLoginSuccess HTTP/1.1" 302  138 "https://localhost:8000/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 Safari/537.36" "-"
https_1  | 2021/11/08 21:25:39 [error] 27#27: *2 connect() failed (110: Connection timed out) while connecting to upstream, client: 172.19.0.1, server: localhost, request: "GET / HTTP/1.1", upstream: "http://192.168.65.1:3000/", host: "localhost", referrer: "https://localhost:8000/"

【讨论】:

我将docker-compose-dev.xml 中的proxy_pass http://host.docker.internal:3000/; 替换为proxy_pass http://172.17.0.1:8000/;,并将dev.conf 中的host.docker.internal:host-gateway 替换为172.17.0.1:host-gateway。认证成功仍然导致https://localhost/#/socialLoginSuccess而不是https://localhost:8000/#/socialLoginSuccess,这里是log。 我在 OP 中添加了更多细节。 > 成功的身份验证仍然导致localhost/#/socialLoginSuccess 而不是localhost:8000/#/socialLoginSuccess 您通常执行此操作的方式是在 443 上针对 nginx 运行所有请求并关闭应用程序端口 (8000) 的防火墙,除了本地主机。然后确保您的身份验证应用程序配置为针对 localhost 工作以避免混淆。从您的日志中,我看到“连接到上游时连接被拒绝...172.17.0.1:8000”。是否有应用程序在该 IP/端口上运行?该应用的日志中是否有错误/崩溃?

以上是关于使用 docker 和 nginx 在 localhost 中调试第三方身份验证的主要内容,如果未能解决你的问题,请参考以下文章

docker 安装nginx

Docker 安装 Nginx

docker安装nginx

docker 安装php

docker 安装php

CentOS中使用Docker安装Nginx