簡體   English   中英

使用 nginx 反向代理后面的 keycloak 保護 nodejs 中的路由

[英]protecting route in nodejs with keycloak behind nginx reverse proxy

我啟動了一個 keycloak 容器:

docker run --name keycloak -p 8080:8080 -e PROXY_ADDRESS_FORWARDING=true -d jboss/keycloak

配置了一個nginx反向代理:

add_header Strict-Transport-Security "max-age=31536000; includeSubdomains;";

server {
    listen 80;
    listen [::]:80;

    server_name 192.168.32.132;

    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl;
    listen [::]:443 ssl;

    server_name 192.168.32.132;

    ssl_certificate     /etc/ssl/private/fullchain.pem;
    ssl_certificate_key /etc/ssl/private/privkey.pem;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

    location /login {
        proxy_pass http://127.0.0.1:9080;

        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-Host    $host;
        proxy_set_header    X-Forwarded-Server  $host;
        proxy_set_header    X-Forwarded-Port    $server_port;
        proxy_set_header    X-Forwarded-Proto   $scheme;

        proxy_buffer_size          128k;
        proxy_buffers              4 256k;
        proxy_busy_buffers_size    256k;

    }

    location /auth {
        proxy_pass http://localhost:8080;

        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-Host    $host;
        proxy_set_header    X-Forwarded-Server  $host;
        proxy_set_header    X-Forwarded-Port    $server_port;
        proxy_set_header    X-Forwarded-Proto   $scheme;

        proxy_buffer_size          128k;
        proxy_buffers              4 256k;
        proxy_busy_buffers_size    256k;
    }

    location /app {
        rewrite ^/app(.*)$ $1 last;
        proxy_pass http://localhost:7080;

        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-Host    $host;
        proxy_set_header    X-Forwarded-Server  $host;
        proxy_set_header    X-Forwarded-Port    $server_port;
        proxy_set_header    X-Forwarded-Proto   $scheme;

        proxy_buffer_size          128k;
        proxy_buffers              4 256k;
        proxy_busy_buffers_size    256k;
        }
    }

然后我啟動了一個 nodeJS 服務器,在用戶可以訪問應用程序之前,它需要一些自定義邏輯:

// Setup Axios HTTP Request client
AXIOS.defaults.baseURL = CONF.URL;
AXIOS.defaults.headers.common['apikey'] = CONF.apiKey;

// Setup keycloak to use the session memoryStore
var memoryStore = new SESSION.MemoryStore();
var keycloak = new KEYCLOAK({ store: memoryStore });

// Set up a server instance and create a session middleware
const APP = EXPRESS();

APP.use(SESSION({
    secret: CRYPTO.randomBytes(512).toString('hex'),
    resave: false,
    saveUninitialized: true,
    store: memoryStore
}));


// Default route handler
APP.get('/login', keycloak.protect(), function(req, res) {
    console.log('%s accessing protected route', req.get('X-Forwarded-For'));
    let sessionID = '';
    let tokenID = '';

    // Dispatch requests to APP's REST Endpoints
    AXIOS({
        method:'POST',
        url: 'session',
        headers: {'Accept': 'application/json'}
    })
    .then(response => {
        if (response.status == 201) {
            sessionID =  response.data['sessionId'];
            console.log('Received session %s', sessionID);
            return AXIOS({
                method:'POST',
                url: 'session/' + sessionID + '/token',
                headers: {'Accept': 'application/json'},
            });
        }
        else throw new ServerError(response);
    })
    .then(response => {
        if (response.status == 201) {
            tokenID =  response.data['tokenId'];
            console.log('Received token %s', tokenID);
            res.redirect('/app/html/createCustomer?' +  QUERYSTRING.encode({'tokenId': tokenID}));
        }
    })
    .catch( error => {console.log('Error', error.message);}
    });
});

APP.use(keycloak.middleware( { logout: '/logout'}));

// Start servers
HTTP.createServer(APP).listen(CONF.serverPort, CONF.serverInterface, () =>         
console.log('Server listening on %s:%d', CONF.serverInterface, 
CONF.serverPort));

其中CONF.serverPort=9080CONF.serverInterface=127.0.0.1

來自 keycloak 服務器管理控制台的 keycloak.json 讀取

{
    "realm": "app-realm",
    "auth-server-url": "https://192.168.32.132/auth",
    "ssl-required": "external",
    "resource": "app-client",
    "public-client": true,
    "confidential-port": 0
}

在 keycloak 管理控制台上,我添加了一位用戶。 客戶端的重定向 URL 設置為通配符。

當我通過路由 /login 訪問 VM 的 IP 192.168.32.132 時,我被重定向到 keycloak 登錄頁面,該頁面告訴我更改用戶的初始密碼。

每次進一步的登錄嘗試都會導致:ERROR_TOO_MANY_REDIRECTS,無論我嘗試什么。

當您嘗試訪問/auth路徑下的 keycloak 時,它會將您重定向到 <keycloak_host>/auth,這會命中反向代理並導致循環。

要修復在/auth和 proxy_pass 之后的 ngnix 配置中添加/

location /auth/ {
   proxy_pass http://localhost:8080/;
   {...}
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM