Короче - у меня есть два приложения Spring Boot с аутентификацией Keycloak, работающие за Nginx, и я хотел бы использовать содержимое App2 в App1 через SSI. Кроме того, требуется единый вход, поэтому нет необходимости входить в оба приложения по отдельности.
Моя настройка следующая:
- Два приложения Spring Boot (App1 и App2), работающие на портах localhost 9000 и 9001 соответственно, обслуживают разметку HTML, которую можно включить в SSI для создания финальной страницы. Оба приложения безопасны и требуют, чтобы пользователь вошел в систему. App1 имеет свой контекст root в
/
, App2 имеет его в /app2
- Сервер Keycloak для управления аутентификацией пользователя с использованием OID C . И App1, и App2 настроены для связи с сервером с помощью Spring Security Keycloak Adapter и зарегистрированы как один клиент в Keycloak
- Я использую Nginx в качестве обратного прокси, с которым сталкивается пользователь. SSI включен. Приложение 1 и Приложение 2 зарегистрированы под двумя отдельными
locations
в конфигурации Nginx. См. Файл nginx.conf
ниже.
Вариант использования, которого я пытаюсь достичь:
- Приложение 1 обслуживает страницу HTML, которая по сути является "оболочкой" приложения - содержит макет и заголовок, нижний колонтитул. В области содержимого есть директива SSI
include virtual
, которая извлекает содержимое из App2. - Итак, в конце концов, я хочу увидеть страницу, обслуживаемую App1, с содержимым из App2.
- Очевидно, что оба приложения требуют входа в систему, но поскольку у меня настроен Keycloak и оба приложения используют одну и ту же область K C и идентификатор клиента, входа в любое из них должно хватить
Что происходит:
- Как только я нажимаю App1, я еще не вошел в систему, я вижу приложение оболочки без какого-либо защищенного содержимого из App1 или App2. Это хорошо.
- Как только я вхожу в приложение App1,
JSESSIONID
устанавливается с помощью cook ie по пути /
. Однако контент из App2 не отображается [который должен был исходить из включения SSI] - Когда я go перехожу на страницу, обслуживаемую App2, оно мгновенно распознает пользователя, и нет необходимости повторно входить в систему, и обслуживается весь защищенный контент. App2 работает нормально. App2 также сохраняет
JSESSIONID
cook ie по пути /app2
.
То, что я пробовал до сих пор:
- Пробовал Nginx готовить ie переписывание пути для сохранения обоих файлов cookie по пути
/
. Это приводит к тому, что два файла cookie конфликтуют и сбрасывают друг друга. - Пытался зарегистрировать App1 и App2 как отдельных клиентов в Keycloak
- Я знаю, что когда страница оболочки, обслуживаемая App1, читается процессор SSI в Nginx, ему необходимо сделать запрос к App2 для заполнения содержимого SSI, но для этого ему нужны соответствующие файлы cookie для App2, чтобы проверить запрос. Пробовал использовать для этого несколько методов проб и ошибок.
Что-то не так с вариантом использования, которого я пытаюсь достичь, или что-то я делаю не так? Spring / Java / Keycloak / Nginx здесь новичок, заранее спасибо.
nginx.conf
файл :
worker_processes 1;
events {
worker_connections 1024;
}
error_log logs/error.log warn;
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name localhost;
ssi on;
client_max_body_size 100M;
port_in_redirect off;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_http_version 1.1;
proxy_set_header X-Forwarded-App-Proto http;
proxy_set_header X-Forwarded-App-Port 80;
# For App1
location / {
proxy_pass http://localhost:9000;
}
# For App2
location /app2/ {
# Notice no trailing / - it means whole URL will be preserved
# i.e., "/app2" will not be discarded from the URL sent to proxy
# which is what we want as our spring app has context root at "/app2"
proxy_pass http://localhost:9001;
# proxy_cookie_path ~*^/.* /; -- This results in conflicts in the two JSESSIONID cookies
}
error_page 302 404 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
application.yml
файлы приложений App1 и App2:
server:
servlet:
contextPath: /app2 # this is just '/' for App1
port: 9001 # this is 9000 for App1
use-forward-headers: true
tomcat:
protocol-header: X-Forwarded-App-Proto
port-header: X-Forwarded-App-Port
########## Keycloak configuration
keycloak:
auth-server-url: http://localhost:8080/auth
realm: AppRealm
resource: AppClient
public-client: true
principal-attribute: preferred_username
security:
disable-csrf: true