Apache2 与 mod_auth_openidc
Apache2 与 mod_auth_openidc(Apache2 with mod_auth_openidc)
目录
mod_auth_openidc 让 Apache2 直接处理完整的 OIDC 认证流程——无需单独的代理容器(OAuth2 Proxy、Authentik Outpost)。Apache 针对你的身份提供方对用户进行认证,并通过 HTTP 请求头把 JWT 访问令牌传给 Wavelog。
架构
Browser → Apache2 (mod_auth_openidc) → Wavelog (PHP-FPM)
↕
Identity Provider (OIDC)
前置条件
安装模块
apt install libapache2-mod-auth-openidc
a2enmod auth_openidc headers
systemctl reload apache2
配置身份提供方
在你的 IdP 中创建一个 OAuth2/OpenID Connect 客户端,包含:
- 重定向 URI:
https://wavelog.example.org/redirect_uri - 客户端类型: 机密(Confidential)
- 记下 Client ID、Client Secret 与 Issuer URL
特定提供方的设置参见:
- Keycloak:Issuer URL 为
https://auth.example.org/realms/example - Authentik:Issuer URL 为
https://auth.example.org/application/o/wavelog/
为会话 cookie 生成一个加密口令:
openssl rand -base64 32
Apache2 虚拟主机
<VirtualHost *:443>
ServerName wavelog.example.org
DocumentRoot /var/www/wavelog
SSLEngine on
SSLCertificateFile /etc/ssl/certs/wavelog.pem
SSLCertificateKeyFile /etc/ssl/private/wavelog.key
# --- mod_auth_openidc ---
OIDCProviderMetadataURL https://auth.example.org/application/o/wavelog/.well-known/openid-configuration
OIDCClientID <your-client-id>
OIDCClientSecret <your-client-secret>
OIDCRedirectURI https://wavelog.example.org/redirect_uri
OIDCCryptoPassphrase <your-random-passphrase>
OIDCScope "openid email profile wavelog_callsign" # scope depends on your identity provider
# Make the access token available as Apache environment variable
OIDCPassAccessToken On
# The redirect URI callback must be handled by mod_auth_openidc, not by CodeIgniter.
# Without this block, CodeIgniter's .htaccess rewrites /redirect_uri to index.php → 404.
<Location "/redirect_uri">
AuthType openid-connect
Require valid-user
</Location>
# Protect only the SSO login endpoint — all other paths remain publicly accessible
<Location "/index.php/header_auth/login">
AuthType openid-connect
Require valid-user
# mod_auth_openidc sets OIDC_access_token as an Apache env var.
# This directive forwards it as an HTTP request header so PHP can read it.
RequestHeader set X-Access-Token "%{OIDC_access_token}e" env=OIDC_access_token
</Location>
<Directory /var/www/wavelog>
Options FollowSymLinks
AllowOverride All
Require all granted
</Directory>
<FilesMatch \.php$>
SetHandler "proxy:unix:/run/php/php8.4-fpm.sock|fcgi://localhost"
</FilesMatch>
</VirtualHost>
重要
只有
/index.php/header_auth/login受保护。Wavelog 的其他所有路径仍可公开访问——这是标准登录表单、API 集成与 ADIF 导入正常工作所必需的。注意(为何需要
RequestHeader)
OIDCPassAccessToken On会让 mod_auth_openidc 把访问令牌存入 Apache 环境变量OIDC_access_token。当 Wavelog 通过SetHandler由 PHP-FPM 提供服务时,该环境变量不会自动作为 HTTP 请求头转发。RequestHeader指令会把它显式转换为X-Access-Token请求头,PHP 将其暴露为HTTP_X_ACCESS_TOKEN。注意(为何
/redirect_uri需要独立的 Location 块)CodeIgniter 的
.htaccess会把所有未知 URL 重写到index.php。如果没有专门的<Location "/redirect_uri">块,Apache 根本不会给 mod_auth_openidc 处理 OIDC 回调的机会——请求会被重写规则捕获并返回 404。加上带AuthType openid-connect的 Location 块,就能告诉 Apache 在重写规则运行之前先把请求交给 mod_auth_openidc。
Wavelog 的 sso.php
mod_auth_openidc 以 X-Access-Token 转发访问令牌,PHP 将其暴露为 HTTP_X_ACCESS_TOKEN:
<?php
// Access token header forwarded by mod_auth_openidc via RequestHeader
$config['auth_header_accesstoken'] = "HTTP_X_ACCESS_TOKEN";
// Logout: redirect to the IdP end-session endpoint
// Keycloak:
// $config['auth_header_url_logout'] = 'https://auth.example.org/realms/example/protocol/openid-connect/logout';
// Authentik:
$config['auth_header_url_logout'] = 'https://auth.example.org/application/o/wavelog/end-session/';
// JWKS endpoint for JWT signature verification
// Keycloak:
// $config['auth_header_jwks_uri'] = 'https://auth.example.org/realms/example/protocol/openid-connect/certs';
// Authentik:
$config['auth_header_jwks_uri'] = 'https://auth.example.org/application/o/wavelog/jwks/';
sso.php 的其他所有设置(声明映射、自动创建等)与各提供方专页中所述相同。
故障排查
/redirect_uri 上返回 404
: CodeIgniter 的重写规则在 mod_auth_openidc 处理之前就捕获了 OIDC 回调。按上文所示添加带 AuthType openid-connect 的 <Location "/redirect_uri"> 块。
SSO Authentication: Missing access token header
: X-Access-Token 请求头没有到达 PHP。请确认已设置 OIDCPassAccessToken On,并且 RequestHeader set X-Access-Token "%{OIDC_access_token}e" env=OIDC_access_token 指令位于 <Location "/index.php/header_auth/login"> 块内。还要确认已启用 mod_headers(a2enmod headers)。
JWT 验证失败
: 检查 auth_header_jwks_uri 是否指向正确的 JWKS 端点,以及 Apache 服务器能否通过网络访问它。在 sso.php 中启用调试日志以查看原始令牌。