使用 Keycloak 授权在 Docker 容器内调用 Quarkus 应用程序时出现 401 Unauthorized

发布于 2025-01-13 05:22:52 字数 1294 浏览 3 评论 0原文

我有一个在 localhost:4200 (角度应用程序)上运行的客户端应用程序,它从 Quarkus 应用程序( localhost:8082 )获取资源。授权是使用Keycloak完成的。

如果我同时启动 Angular 和 Angular,授权就可以正常工作。我的本地主机上的 Quarkus 应用程序: 输入图片此处的描述

但是,如果我使用 Quarkus 应用程序构建 Docker 映像并在 Docker 容器内运行它,则它不起作用。 Angular 应用程序仍然在我的本地主机上运行,​​而不是在容器内运行:

在此处输入图像描述

我的 Quarkus application.properties:

quarkus.http.port=8082
quarkus.oidc.auth-server-url=http://${KEYCLOAK_HOST:localhost}:${KEYCLOAK_PORT:8081}/auth/realms/the-realm
quarkus.oidc.client-id=the-api
quarkus.oidc.credentials.secret=secret
quarkus.oidc.authentication.scopes=profile

quarkus.http.cors.origins=http://localhost:4200
quarkus.http.cors.methods=GET,PUT,POST,PATCH,DELETE,OPTIONS
quarkus.http.cors.headers=accept, authorization, content-type, x-requested-with
quarkus.http.cors=true

发生这种情况是因为容器内的 localhost 不引用我机器的 localhost 吗?那么这个属性将不起作用: quarkus.http.cors.origins=http://localhost:4200 ?我尝试使用 quarkus.http.cors.origins=http://host.docker.internal:4200 ,但它不起作用。

作为初学者,任何建议都值得赞赏,谢谢!

I have a client app running on  localhost:4200  (angular app) that gets resources from a Quarkus app( localhost:8082 ). The authorization is done using  Keycloak .

The authorization works fine if I start both Angular & Quarkus apps on my localhost:
enter image description here

However, it does not work if I build a Docker image with my Quarkus app and run it inside a Docker container. Angular app still runs on my localhost, not inside a container:

enter image description here

My Quarkus application.properties:

quarkus.http.port=8082
quarkus.oidc.auth-server-url=http://${KEYCLOAK_HOST:localhost}:${KEYCLOAK_PORT:8081}/auth/realms/the-realm
quarkus.oidc.client-id=the-api
quarkus.oidc.credentials.secret=secret
quarkus.oidc.authentication.scopes=profile

quarkus.http.cors.origins=http://localhost:4200
quarkus.http.cors.methods=GET,PUT,POST,PATCH,DELETE,OPTIONS
quarkus.http.cors.headers=accept, authorization, content-type, x-requested-with
quarkus.http.cors=true

Does this happen because localhost inside a container does not refer to my machine's localhost ? So this property will have no effect: quarkus.http.cors.origins=http://localhost:4200 ? I tried using quarkus.http.cors.origins=http://host.docker.internal:4200 but it did not work..

As a beginner, any advice is apreciated, thank you !

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

緦唸λ蓇 2025-01-20 05:22:52

只是为了补充这一点。
我按照上面的建议做了,并阅读了有趣的“更多详细信息”链接,这确实帮助我理解了这个问题,但问题仍然存在。

我最终让它发挥作用,并想扩展上面接受的答案。

正如答案中提到的,需要在领域 Frontend URL 属性中输入正确的值。 Frontend URL 表示“您的前端应用程序用于进行身份验证的 Keycloak 公共 url”。

因此,就我而言,我在内部网络 (flowt-net) 上的容器中使用 Keycloak 20.0.2,以便我的 Quarkus 应用程序可以找到它。我有一个 Vue 3 应用程序来测试身份验证。

这是一个开发测试上下文,因此不是有关密码、CORS 等的最佳实践。

Keycloak docker 运行:

docker run --name keycloak --net flowt-net -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=admin -p 8543:8080 -v keycloak:/opt/keycloak/data/h2 quay.io/keycloak/keycloak:latest start-dev

网络按照 --net flowt-net 设置。

我还有一个名为 keycloak 的 docker 卷来保存内置的 H2 数据库 (-v keycloak:/opt/keycloak/data/h2)

为了进行测试,我从来自 https://quarkus.io/guides/security-openid-connect 的示例应用程序

相关的Quarkus 应用 application.properties

quarkus.http.cors=true
quarkus.http.cors.origins=*

# See note below 
quarkus.oidc.auth-server-url=http://keycloak:8080/realms/quarkus

quarkus.oidc.credentials.secret=MySecretFromKeycloakClientHere
quarkus.oidc.client-id=backend-service

http://keycloak:8080/realms/quarkus 引用名为 keycloak 的 keycloak 容器的 url( --name keycloak)在内部docker网络上,端口8080是KC内部端口。即按照-p 8543:8080

Quarkus 应用程序 docker 构建:

./mvnw package;

docker build -f src/main/docker/Dockerfile.jvm -t flowt-org-jvm .

docker run -i --rm --net flowt-net --name myquarkusapp -p 10000:8080 flowt-org-jvm

我现在正在使用 JVM 映像测试 dockerization。

Vue 应用程序按如下方式进行身份验证,我将其设置为在 localhost:3123 而不是 localhost:8080 上运行,因此当我试图了解“动物园里的谁是谁”时,我不会对 KC 内部端口号感到困惑。

import { createApp } from 'vue'
import App from './App.vue'
import { vueKeycloak } from '@baloise/vue-keycloak'
import { vueAxios } from '@baloise/vue-axios'

createApp(App)
  .use(vueKeycloak, {
    initOptions: {
      flow: 'standard', // default
      checkLoginIframe: false, // default
      onLoad: 'login-required', // default
    },
    config: {
      url: 'http://localhost:8543/',
      realm: 'quarkus',
      clientId: 'frontend-app'
    }
  })
  .use(vueAxios, {
    // The Quasar app
    baseURL: '',
  })
  .mount('#app');

有关 vueKeycloak 和 vueAxios 的更多信息,请参阅 https://github.com/baloise/vue-keycloak

我的 Quarkus 应用程序的 Vue axios 端点是例如 http://localhost:10000/api/users/me

注意:对于构建的 Keycloak 的最新版本使用 Quarkus,身份验证 URL 为 http://localhost:8543/ 不是 http://localhost:8543/auth

给定带有 -p 8543:8080 的 Keycloak 映像,您可以使用外部/公共端口,即本例中的 8543

因此,在 Quarkus 领域的 Keycloak 管理中,Frontend URL 在我的情况下也需要是 http://localhost:8543/,而不是 http:// /localhost:8543/auth 这是一些较旧的 SO 帖子所建议的。

理论上这应该有效,但事实并非如此。我仍然收到 401 错误。

难题中缺少的部分是我需要删除现有的 Quarkus 应用程序及其所有层,然后从头开始重建。一旦我这样做了,它就神奇地起作用了,我在 Vue 应用程序中的 api 调用开始返回 200。耶!

我希望能为某人节省一些时间!

走好,
穆雷

Just to add to this.
I did as suggested above and read the interesting "more details" link which certainly helped me understand the issue, but the problem remained.

I eventually got it working and wanted to expand on the accepted answer above.

As mentioned in the answer, one needs to put the right value in the realm Frontend URL property. Frontend URL means "the Keycloak public url that your front end app uses to authenticate with".

So, in my case, I am using Keycloak 20.0.2 in a container on an internal network (flowt-net) so my Quarkus app could find it. I have a Vue 3 app to test the authentication.

This is a development test context so is not best practice re passwords, CORS, etc.

The Keycloak docker run:

docker run --name keycloak --net flowt-net -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=admin -p 8543:8080 -v keycloak:/opt/keycloak/data/h2 quay.io/keycloak/keycloak:latest start-dev

The network is set as per --net flowt-net.

I also have a docker volume called keycloak to persist the built-in H2 database (-v keycloak:/opt/keycloak/data/h2)

For testing I started with the example app from https://quarkus.io/guides/security-openid-connect

The relevant Quarkus app application.properties:

quarkus.http.cors=true
quarkus.http.cors.origins=*

# See note below 
quarkus.oidc.auth-server-url=http://keycloak:8080/realms/quarkus

quarkus.oidc.credentials.secret=MySecretFromKeycloakClientHere
quarkus.oidc.client-id=backend-service

The http://keycloak:8080/realms/quarkus refers to the url of the keycloak container named keycloak (--name keycloak) on the internal docker network, and the port 8080 is the KC internal port. ie as per -p 8543:8080.

The Quarkus app docker build:

./mvnw package;

docker build -f src/main/docker/Dockerfile.jvm -t flowt-org-jvm .

docker run -i --rm --net flowt-net --name myquarkusapp -p 10000:8080 flowt-org-jvm

I am testing the dockerisation by using the JVM image for now.

The Vue app authenticates as below and I set it to run on localhost:3123 instead of localhost:8080 so I didn't get confused with the KC internal port number when I was trying to understand "who is who in the zoo".

import { createApp } from 'vue'
import App from './App.vue'
import { vueKeycloak } from '@baloise/vue-keycloak'
import { vueAxios } from '@baloise/vue-axios'

createApp(App)
  .use(vueKeycloak, {
    initOptions: {
      flow: 'standard', // default
      checkLoginIframe: false, // default
      onLoad: 'login-required', // default
    },
    config: {
      url: 'http://localhost:8543/',
      realm: 'quarkus',
      clientId: 'frontend-app'
    }
  })
  .use(vueAxios, {
    // The Quasar app
    baseURL: '',
  })
  .mount('#app');

See https://github.com/baloise/vue-keycloak for more on vueKeycloak and vueAxios.

My Vue axios end point for the Quarkus app is eg http://localhost:10000/api/users/me

Note: for the more recent versions of Keycloak which were built using Quarkus, the authentication url is http://localhost:8543/ not http://localhost:8543/auth.

Given the Keycloak image with -p 8543:8080 you use your external / public port ie 8543 in this case.

In Keycloak admin for the Quarkus realm, the Frontend URL therefore needs to also be http://localhost:8543/ in my case, and not http://localhost:8543/auth which some older SO posts suggest.

Theoretically that should have worked, but it didn't. I was still getting 401 errors.

The missing piece in the puzzle was that I needed to remove my existing Quarkus app and all its layers and rebuild it from scratch. Once I did that, it magically worked and my api calls in the Vue app started returning 200. Yay!

I hope that save someone some hours!

Go well,
Murray

記柔刀 2025-01-20 05:22:52

最后,这不是 CORS 问题,正如评论中提到的(谢谢@sventorben!),解决方案是进入 Keycloak 领域设置并添加 http://localhost:8081/auth 对于前端 URL

在此处输入图像描述

更多详细信息:https://stackoverflow.com/a/70708121/16357334

In the end it wasn't a CORS problem, as mentioned in the comments (thank you @sventorben!), the solution was to go into Keycloak realm settings and add http://localhost:8081/auth for Frontend URL:

enter image description here

More details here: https://stackoverflow.com/a/70708121/16357334

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文