Keycloak
Keycloak
目录
- 架构(OAuth2 Proxy)
- 步骤 1:创建 Keycloak 客户端
- 步骤 2:添加呼号声明
- 步骤 3:配置 OAuth2 Proxy
- 步骤 4:配置你的 Web 服务器
- 步骤 5:配置 Wavelog
- 步骤 5:验证
提示:已经运行 Apache2?改用 mod_auth_openidc
如果 Apache2 是你的 Web 服务器,推荐使用
mod_auth_openidc——它原生处理 OIDC 流程,无需单独的 OAuth2 Proxy 容器。参见 Apache2 配合 mod_auth_openidc。
本指南介绍如何将 Keycloak 配置为 Wavelog 的身份提供方。涵盖两种方案:
- OAuth2 Proxy(步骤 3–5):由专用的代理容器处理 OIDC 流程,并将 JWT 转发给 Wavelog
- Apache2 配合 mod_auth_openidc(步骤 4 中的备选方案):由 Apache 直接处理 OIDC,无需单独的代理
架构(OAuth2 Proxy)
Browser → Webserver (nginx / Apache2) → OAuth2 Proxy → Wavelog
↕
Keycloak (JWKS)
OAuth2 Proxy 负责与 Keycloak 之间的 OIDC 流程,并将 JWT 访问令牌以 HTTP 请求头的形式转发给 Wavelog。Wavelog 使用 Keycloak 的 JWKS 端点校验该令牌。
步骤 1:创建 Keycloak 客户端
在 Keycloak 管理控制台中:
- 进入 客户端(Clients)→ 创建客户端(Create client)
- 设置 客户端 ID(Client ID),例如
wavelog - 点击 下一步(Next)
- 启用 客户端认证(Client authentication)
- 点击 下一步(Next),然后配置重定向 URI:
- 根 URL:
https://wavelog.example.org/ - 主页 URL:
https://wavelog.example.org/ - 有效重定向 URI:
https://wavelog.example.org/* - 登出后有效重定向 URI:
https://wavelog.example.org/*
- 根 URL:
- 保存
保存后,进入 凭证(Credentials)标签页并复制 客户端密钥(Client Secret)。
步骤 2:添加呼号声明
Wavelog 要求 JWT 中包含呼号。默认情况下,Keycloak 不会在令牌中包含自定义用户属性。
2a. 添加用户属性
-
进入 领域设置(Realm Settings)→ 用户配置文件(User profile)→ 创建属性:
- 名称:
callsign - 显示名称:
Callsign - 必填: 可选(取决于你的使用场景)
- 名称:
-
进入 用户(Users)→ 选择一个用户,并为 callsign 属性添加值(例如
4W7EST)
2b. 创建协议映射器
- 进入 客户端(Clients)→ 选择你的客户端 → 客户端范围(Client scopes)→ 点击专用范围(例如
wavelog-dedicated) - 点击 添加映射器(Add mapper)→ 按配置(By configuration)→ 用户属性(User Attribute)
- 配置:
- 名称:
callsign - 用户属性:
callsign - 令牌声明名称:
callsign - 声明 JSON 类型:
String - 启用 添加到访问令牌(Add to access token)
- 名称:
- 保存
提示
如果你的设置使用用户组来分配呼号,也可以使用
nickname这类已有属性,或从用户组进行映射。
步骤 3:配置 OAuth2 Proxy
OAuth2 Proxy 充当认证反向代理。它负责与 Keycloak 之间的 OIDC 登录流程,并将 JWT 访问令牌转发给 Wavelog。
重要
OAuth2 Proxy 必须仅保护
/index.php/header_auth/login。所有其他 Wavelog 路径都必须在无需认证的情况下直接放行。
Docker Compose
services:
oauth2-proxy:
image: quay.io/oauth2-proxy/oauth2-proxy:latest
command: --config /oauth2-proxy.cfg
volumes:
- "./oauth2-proxy.cfg:/oauth2-proxy.cfg"
restart: unless-stopped
ports:
- "4180:4180"
oauth2-proxy.cfg
详细说明请参阅 OAuth2 Proxy 官方文档。
http_address = "0.0.0.0:4180"
cookie_secret = "your-random-cookie-secret" # see below how to generate
provider = "keycloak-oidc"
email_domains = ["*"]
client_id = "your-client-id"
client_secret = "your-client-secret"
redirect_url = "https://your-wavelog-domain/oauth2/callback"
oidc_issuer_url= "https://your-keycloak-domain/realms/your-realm"
code_challenge_method="S256"
pass_user_headers=true
set_xauthrequest = true
pass_access_token = true
# See https://oauth2-proxy.github.io/oauth2-proxy/configuration/session_storage
cookie_refresh = "4m"
cookie_expire = "30m"
skip_provider_button = true
whitelist_domains = "your-keycloak-domain"
使用以下命令生成 cookie 密钥:
openssl rand -base64 32 | tr -- '+/' '-_'
注意
pass_access_token = true会让 OAuth2 Proxy 将 JWT 以X-Forwarded-Access-Token请求头转发,这也是 Wavelog 默认读取的内容。
步骤 4:配置你的 Web 服务器
OAuth2 Proxy 监听 4180 端口,并作为你的 Web 服务器的上游。Web 服务器负责终止 TLS 并代理所有流量。
提示:示例
以下所有这些配置都只是示例。你必须根据自身需求调整全部内容。这里没有可以直接复制粘贴的解决方案。
nginx
upstream app {
server wavelog:80;
}
upstream oauth2_proxy {
server oauth2-proxy:4180;
}
server {
listen 80;
server_name wavelog.example.org;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name wavelog.example.org;
ssl_certificate /etc/nginx/ssl/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/privkey.key;
# oauth2-proxy endpoints — OIDC-Flow (Callback, Sign-in, etc.)
location /oauth2/ {
proxy_pass http://oauth2-proxy:4180;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme $scheme;
proxy_set_header X-Auth-Request-Redirect $request_uri;
# These buffer settings are recommended for larger JWTs to prevent 502 errors from nginx
proxy_buffer_size 16k;
proxy_buffers 4 16k;
proxy_busy_buffers_size 16k;
}
# SSO-Login via header_auth: oauth2-proxy authenticates, JWT is forwarded to Wavelog
location = /oauth2/auth {
proxy_pass http://oauth2-proxy:4180;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header X-Original-URI $request_uri;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme $scheme;
proxy_buffer_size 16k;
proxy_buffers 4 16k;
proxy_busy_buffers_size 16k;
}
# All other requests go directly to Wavelog, which manages sessions itself (no auth_request)
location ^~ /index.php/header_auth/ {
auth_request /oauth2/auth;
# Not authenticated → directly start Keycloak login (no splash screen)
error_page 401 = @sso_start;
# Forward JWT access token from oauth2-proxy to Wavelog as a header
auth_request_set $access_token $upstream_http_x_auth_request_access_token;
proxy_set_header X-Forwarded-Access-Token $access_token;
proxy_pass http://app:8084;
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-Proto $scheme;
}
# Start Keycloak flow (triggered by @sso_start)
location @sso_start {
return 302 /oauth2/start?rd=/index.php/header_auth/login;
}
# All other routes — no auth_request, Wavelog manages sessions itself
location / {
proxy_pass http://app:8084;
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-Proto $scheme;
}
}
Apache2
<VirtualHost *:443>
ServerName wavelog.example.org
# Proxy the SSO login endpoint to OAuth2 Proxy for authentication
<Location "/index.php/header_auth">
ProxyPass http://oauth2-proxy:4180
ProxyPassReverse http://oauth2-proxy:4180
RequestHeader unset Authorization
</Location>
# All other requests go directly to Wavelog, which manages sessions itself (no auth_request)
ProxyPass / http://wavelog-app:8084/
ProxyPassReverse / http://wavelog-app:8084/
</VirtualHost>
步骤 5:配置 Wavelog
application/config/config.php:
<?php
$config['auth_header_enable'] = true;
application/config/sso.php(从 sso.sample.php 复制):
<?php
$config['auth_header_create'] = true;
$config['auth_header_allow_direct_login'] = false;
$config['auth_header_hide_password_field']= true;
$config['auth_header_accesstoken'] = "HTTP_X_FORWARDED_ACCESS_TOKEN";
$config['auth_header_text'] = "Login with SSO";
// Keycloak logout via OAuth2 Proxy
$config['auth_header_url_logout'] = 'https://wavelog.example.org/oauth2/sign_out'
. '?rd=https://auth.example.org/realms/example/protocol/openid-connect/logout';
// Keycloak JWKS endpoint — enables cryptographic JWT verification
// You can get all necessary URL values from the Keycloak Admin Console → Realm Settings → Endpoints
$config['auth_header_jwks_uri'] = 'https://auth.example.org/realms/example/protocol/openid-connect/certs';
$config['auth_headers_claim_config'] = [
'user_name' => [
'claim' => 'preferred_username',
'override_on_update' => true,
'allow_manual_change' => false,
],
'user_email' => [
'claim' => 'email',
'override_on_update' => true,
'allow_manual_change' => false,
],
'user_callsign' => [
'claim' => 'callsign',
'override_on_update' => true,
'allow_manual_change' => false,
],
'user_firstname' => [
'claim' => 'given_name',
'override_on_update' => true,
'allow_manual_change' => true,
],
'user_lastname' => [
'claim' => 'family_name',
'override_on_update' => true,
'allow_manual_change' => true,
],
];
将 auth.example.org 和 /realms/example 替换为你实际的 Keycloak 域名与领域名称。
步骤 5:验证
- 在浏览器中打开 Wavelog——应出现 SSO 登录按钮
- 点击该按钮并完成 Keycloak 登录
- 你应被重定向到 Wavelog 仪表盘
如果出现问题,可在 sso.php 和 config.php 中启用调试日志,以便检查 JWT 声明:
<?php
// sso.php
$config['auth_header_debug_jwt'] = true;
// config.php
$config['log_threshold'] = 2;
在 application/logs/log-YYYY-MM-DD.php 中查看解码后的 JWT 载荷。确认 callsign、email 和 preferred_username 均存在,且与你配置的声明映射一致。
警告
排障完成后请再次禁用
auth_header_debug_jwt。