python - Flask_oidc 在 Docker 容器中运行时给出“Errno 99 无法分配请求的地址”
问题描述
目标:
在 Docker 容器中运行的 Flask 应用程序中使用 OIDC。
背景:
我正在使用 Flask 构建一个 Web 应用程序,并希望使用 Keycloak 来提供访问权限。为此,我使用 Python 库 flask_oidc。
所有服务都使用 docker-compose 文件在本地运行:
- 运行 Flask 应用程序的 Gunicorn(端口 5000)
- 钥匙斗篷(端口 8080)
我遵循了https://gist.github.com/thomasdarimont/145dc9aa857b831ff2eff221b79d179a的示例,甚至将我的应用程序简化为这个。
问题:
- 启动所有服务
- 导航到需要登录的服务(
/private
在示例中) - 用户被重新路由到提示登录的 Keycloud 服务器。
- 用户登录。
- Keycloak 将用户路由回应用程序 (
/oidc_callback
) - !!!Flask 应用程序因
OSError: [Errno 99] Cannot assign requested address
错误而崩溃。
这是在尝试连接到 Keycloak 服务器时在flask_oidc
> oauth2client
>中引起的。httplib2
我认为正在发生的是库尝试打开与 Keycloak 服务器的连接,但尝试将其绑定到localhost
. 这可能会失败,因为在 Docker 容器内,应用程序绑定到0.0.0.0
.
我尝试了什么:
[ WORKS ] 在容器外运行 Gunicorn/Flask 应用程序,并在容器内运行 Keylcoak。
这表明(对我而言)我的所有设置和代码都很好,但问题出在 Docker<-->flask_oidc+ 之间的交互中。
问题:谁能解释一下?我真的希望有人有一个工作设置(在 docker 中使用 flask_oidc 的 Flask),并且愿意分享这个。
更新 [2018 年 5 月 12 日] 我想我明白了。我使用 PyOIDC 手动完成所有步骤并能够进行调试。
在您自己的计算机 ( localhost
) 上在 Docker 中运行这两个服务时,您会遇到冲突:
- 用户去
localhost:8080
寻找Keycloak并localhost:5000
找到应用程序。 - Flask 应用程序在容器内运行,
localhost
不会解析到主机,而是解析到容器内的自身。 - 您可以让 Flask 连接到
http://keycloak/
使用容器中的网络,但随后它会返回该域下的所有配置。这很糟糕,因为对外界来说它应该是localhost:8080
。
现在,如果您实际上有域名(例如 keycloak.awesome.app 和 app.awesome.app),我认为它会正常工作,因为它会使用外部 DNS 将其解析为 IP 地址,即正确的机器。
奖励: PyOIDC 可以从 Keycloak 中检索提供程序配置,因此无需为此手动输入。耶!
新设置 对于本地开发,我决定进行如下设置:
(1) 添加到/etc/hosts
:
127.0.0.1 keycloak.dev.local
127.0.0.1 app.dev.local
(2) 添加到您的 Flask 服务中docker-compose.yml
:
extra_hosts: #host.docker.internal is not accepted.
- "keycloak.dev.local:<YOUR IP ADRESS>"
- "app.dev.local:<YOUR IP ADRESS>"
(=) 现在,您和 Flask 应用程序都可以访问keycloak.dev.local
并且可以正确响应!
请注意,我仍然希望有一个更好的解决方案。一旦我的 IP 地址更改,此设置就会失败。
解决方案
flask-oidc 从客户端机密文件中获取令牌端点配置。
我设法通过进行以下更改使其工作:
- 为烧瓶应用和keycloak容器创建了一个 docker 网络;
- 编辑了属性userinfo_uri、token_uri和token_introspection_uri,将主机名替换为 keycloak 容器主机名(我使用的是 docker-compose,在这种情况下,keycloak 容器主机名是服务名称)。
例子:
{
"web": {
"auth_uri": "http://localhost:8080/auth/realms/REMOVED/protocol/openid-connect/auth",
"client_id": "flask-client",
"client_secret": "REMOVED",
"redirect_uris": ["http://localhost:5000/oidc_callback"],
"userinfo_uri": "http://keycloak:8080/auth/realms/REMOVED/protocol/openid-connect/userinfo",
"token_uri": "http://keycloak:8080/auth/realms/REMOVED/protocol/openid-connect/token",
"token_introspection_uri": "http://keycloak:8080/auth/realms/REMOVED/protocol/openid-connect/token/introspect"
}
}
现在它通过 docker 网络连接以交换令牌信息。
推荐阅读
- ios - 侧载颤振iOS应用程序时出现空白屏幕
- swift - 快速选择器不选择项目
- c++ - 如何将重载中的第二个参数传递给 std::visit?
- google-cloud-logging - 如何在 GCP 日志记录中保留混合大小写,因为目前它显示全部小写?
- c# - 视觉错误代码 C1002 - 玩家移动问题 - 已修复
- python - 在 Python 中将文本文件转换为数据框
- c# - 自动用于 .net 核心中的开发和发布
- java - 在 Java 中展平数组
- c - 需要在 Matplotlib 中显示连接所有点的线的轨迹,但需要在 C 中编码
- arrays - 循环 VBA 范围并偏移到特定表列和其他值