This commit is contained in:
Bastian Wagner
2026-07-15 16:03:49 +02:00
parent d51d915c74
commit 9cd8891769
8 changed files with 19 additions and 50 deletions

View File

@@ -3,7 +3,7 @@ NODE_ENV=development
API_PORT=3000 API_PORT=3000
WEB_PORT=4200 WEB_PORT=4200
PUBLIC_WEB_URL=http://localhost:4200 PUBLIC_WEB_URL=http://localhost:4200
API_BASE_URL= API_BASE_URL=/api
DATABASE_URL=mysql://ldap_portal:change-me@mysql.example.com:3306/ldap_portal DATABASE_URL=mysql://ldap_portal:change-me@mysql.example.com:3306/ldap_portal
DATABASE_SSL=false DATABASE_SSL=false

View File

@@ -58,7 +58,7 @@ docker run -d --name ldap-portal-idp \
registry.example.com/ldap-portal/idp:latest registry.example.com/ldap-portal/idp:latest
``` ```
Standardmaessig bleibt `API_BASE_URL` leer. Das Frontend nutzt dadurch relative URLs und Nginx routet API-/OIDC-Pfade intern zur NestJS-API. Setze `API_BASE_URL` nur, wenn das Frontend bewusst eine andere API-Origin verwenden soll. Standardmaessig ist `API_BASE_URL=/api`. Das Frontend ruft damit Backend-Endpunkte unter `/api/...` auf, waehrend Nginx den Prefix intern entfernt und zur NestJS-API routet. Dadurch bleiben Angular-Routen wie `/account` und `/admin/users` auch nach einem Browser-Refresh SPA-Routen. Setze `API_BASE_URL` nur anders, wenn das Frontend bewusst eine andere API-Origin verwenden soll; bei Single-Container-Deployments sollte `/api` bleiben.
## Externe Dienste ## Externe Dienste

View File

@@ -14,29 +14,12 @@
"secure": false, "secure": false,
"changeOrigin": true "changeOrigin": true
}, },
"/auth": { "/api": {
"target": "http://localhost:3000", "target": "http://localhost:3000",
"secure": false, "secure": false,
"changeOrigin": true "changeOrigin": true,
}, "pathRewrite": {
"/account": { "^/api": ""
"target": "http://localhost:3000", }
"secure": false,
"changeOrigin": true
},
"/admin": {
"target": "http://localhost:3000",
"secure": false,
"changeOrigin": true
},
"/password": {
"target": "http://localhost:3000",
"secure": false,
"changeOrigin": true
},
"/registration": {
"target": "http://localhost:3000",
"secure": false,
"changeOrigin": true
} }
} }

View File

@@ -83,11 +83,11 @@ interface CreatedOidcClient extends OidcClient {
<article class="info-panel"> <article class="info-panel">
<h2>Discovery</h2> <h2>Discovery</h2>
<dl> <dl>
<div><dt>Configuration</dt><dd>{{ apiBaseUrl }}/.well-known/openid-configuration</dd></div> <div><dt>Configuration</dt><dd>{{ oidcBaseUrl }}/.well-known/openid-configuration</dd></div>
<div><dt>Authorize</dt><dd>{{ apiBaseUrl }}/oidc/auth</dd></div> <div><dt>Authorize</dt><dd>{{ oidcBaseUrl }}/oidc/auth</dd></div>
<div><dt>Token</dt><dd>{{ apiBaseUrl }}/oidc/token</dd></div> <div><dt>Token</dt><dd>{{ oidcBaseUrl }}/oidc/token</dd></div>
<div><dt>UserInfo</dt><dd>{{ apiBaseUrl }}/oidc/me</dd></div> <div><dt>UserInfo</dt><dd>{{ oidcBaseUrl }}/oidc/me</dd></div>
<div><dt>JWKS</dt><dd>{{ apiBaseUrl }}/oidc/jwks</dd></div> <div><dt>JWKS</dt><dd>{{ oidcBaseUrl }}/oidc/jwks</dd></div>
</dl> </dl>
</article> </article>
</section> </section>
@@ -134,6 +134,7 @@ export class AdminOidcClientsComponent implements OnInit {
readonly failed = signal(false); readonly failed = signal(false);
readonly message = signal(''); readonly message = signal('');
readonly createdSecret = signal(''); readonly createdSecret = signal('');
readonly oidcBaseUrl: string;
readonly form; readonly form;
constructor( constructor(
@@ -141,6 +142,7 @@ export class AdminOidcClientsComponent implements OnInit {
private readonly http: HttpClient, private readonly http: HttpClient,
@Inject(API_BASE_URL) readonly apiBaseUrl: string, @Inject(API_BASE_URL) readonly apiBaseUrl: string,
) { ) {
this.oidcBaseUrl = apiBaseUrl.endsWith('/api') ? apiBaseUrl.slice(0, -4) : apiBaseUrl;
this.form = this.fb.nonNullable.group({ this.form = this.fb.nonNullable.group({
clientName: ['', Validators.required], clientName: ['', Validators.required],
redirectUris: ['http://localhost:8080/callback', Validators.required], redirectUris: ['http://localhost:8080/callback', Validators.required],

View File

@@ -1,3 +1,3 @@
window.__LDAP_PORTAL_CONFIG__ = { window.__LDAP_PORTAL_CONFIG__ = {
apiBaseUrl: '' apiBaseUrl: '/api'
}; };

View File

@@ -66,6 +66,6 @@ bootstrapApplication(AppComponent, {
provideRouter(routes), provideRouter(routes),
provideHttpClient(withInterceptors([authInterceptor])), provideHttpClient(withInterceptors([authInterceptor])),
AuthService, AuthService,
{ provide: API_BASE_URL, useValue: window.__LDAP_PORTAL_CONFIG__?.apiBaseUrl ?? '' }, { provide: API_BASE_URL, useValue: window.__LDAP_PORTAL_CONFIG__?.apiBaseUrl ?? '/api' },
], ],
}).catch((error) => console.error(error)); }).catch((error) => console.error(error));

View File

@@ -26,24 +26,8 @@ server {
proxy_pass http://127.0.0.1:3000; proxy_pass http://127.0.0.1:3000;
} }
location /auth/ { location /api/ {
proxy_pass http://127.0.0.1:3000; proxy_pass http://127.0.0.1:3000/;
}
location /account/ {
proxy_pass http://127.0.0.1:3000;
}
location /admin/ {
proxy_pass http://127.0.0.1:3000;
}
location /password/ {
proxy_pass http://127.0.0.1:3000;
}
location /registration/ {
proxy_pass http://127.0.0.1:3000;
} }
location / { location / {

View File

@@ -3,7 +3,7 @@ set -eu
cat >/usr/share/nginx/html/config.js <<EOF cat >/usr/share/nginx/html/config.js <<EOF
window.__LDAP_PORTAL_CONFIG__ = { window.__LDAP_PORTAL_CONFIG__ = {
apiBaseUrl: "${API_BASE_URL:-}" apiBaseUrl: "${API_BASE_URL:-/api}"
}; };
EOF EOF