Keycloak

Keycloak

目录

提示:已经运行 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 管理控制台中:

  1. 进入 客户端(Clients)→ 创建客户端(Create client)
  2. 设置 客户端 ID(Client ID),例如 wavelog
  3. 点击 下一步(Next)
  4. 启用 客户端认证(Client authentication)
  5. 点击 下一步(Next),然后配置重定向 URI:
    • 根 URL: https://wavelog.example.org/
    • 主页 URL: https://wavelog.example.org/
    • 有效重定向 URI: https://wavelog.example.org/*
    • 登出后有效重定向 URI: https://wavelog.example.org/*
  6. 保存

保存后,进入 凭证(Credentials)标签页并复制 客户端密钥(Client Secret)。


步骤 2:添加呼号声明

Wavelog 要求 JWT 中包含呼号。默认情况下,Keycloak 不会在令牌中包含自定义用户属性。

2a. 添加用户属性

  1. 进入 领域设置(Realm Settings)→ 用户配置文件(User profile)→ 创建属性:

    • 名称: callsign
    • 显示名称: Callsign
    • 必填: 可选(取决于你的使用场景)
  2. 进入 用户(Users)→ 选择一个用户,并为 callsign 属性添加值(例如 4W7EST)

2b. 创建协议映射器

  1. 进入 客户端(Clients)→ 选择你的客户端 → 客户端范围(Client scopes)→ 点击专用范围(例如 wavelog-dedicated)
  2. 点击 添加映射器(Add mapper)→ 按配置(By configuration)→ 用户属性(User Attribute)
  3. 配置:
    • 名称: callsign
    • 用户属性: callsign
    • 令牌声明名称: callsign
    • 声明 JSON 类型: String
    • 启用 添加到访问令牌(Add to access token)
  4. 保存

提示

如果你的设置使用用户组来分配呼号,也可以使用 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:验证

  1. 在浏览器中打开 Wavelog——应出现 SSO 登录按钮
  2. 点击该按钮并完成 Keycloak 登录
  3. 你应被重定向到 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。

Wavelog 手册(中文版) / Keycloak 0 字 0 行 bg8lng
2026-10-21T12:42:36.065467625Z 2026-10-21T12:43:42.342035404Z