You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

OpenID Connect 客户端无需调用IdP的Token验证及PHP实现咨询

方案可行性说明

该方案完全可行。OIDC的ID Token、Access Token本质都是自包含的JWT结构,本地验证是标准的token校验方案,相比调用Keycloak的token内省端点性能高很多,非常适合你提到的受控内网环境场景。

中间件必备信息
  • Keycloak对应Realm的RS256签名公钥:Keycloak默认使用非对称加密RS256算法签名JWT,仅需公钥即可完成验签,无需掌握私钥
  • 匹配的签发者(iss)字段:格式一般为http(s)://<你的Keycloak服务地址>/realms/<realm名称>,必须和token内的iss声明完全一致
  • 允许的受众(aud)列表:ID Token的aud默认是你的客户端ID,Access Token的aud对应你配置的资源服务器标识,校验时需匹配预期值
  • 可选校验规则:比如允许的scope列表、自定义声明校验规则,可根据业务需求补充
PHP实现步骤

1. 安装依赖

推荐使用主流的firebase/php-jwt库处理JWT校验,执行composer命令安装:
composer require firebase/php-jwt

2. 获取Keycloak公钥

登录Keycloak管理后台,进入对应Realm,依次点击「Realm settings」→「Keys」标签,找到算法为RS256的条目,点击右侧「Public key」按钮复制公钥内容,给内容补充首尾标识后得到完整PEM格式公钥:

-----BEGIN PUBLIC KEY-----
你复制的公钥内容
-----END PUBLIC KEY-----

3. 验证代码示例

<?php
require __DIR__ . '/vendor/autoload.php';

use Firebase\JWT\JWT;
use Firebase\JWT\Key;
use Firebase\JWT\ExpiredException;
use Firebase\JWT\BeforeValidException;
use Firebase\JWT\SignatureInvalidException;

// 配置项,替换为你自己的实际值
$keycloakPublicKey = <<<EOD
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx... 这里替换成你的公钥内容
-----END PUBLIC KEY-----
EOD;
$expectedIss = 'https://your-keycloak-domain.com/realms/your-realm';
$allowedAud = ['your-client-id', 'your-resource-server-id']; // 允许的受众列表

function validateKeycloakToken(string $token, string $publicKey, string $expectedIss, array $allowedAud): array|bool
{
    try {
        $decoded = JWT::decode($token, new Key($publicKey, 'RS256'));
        // 转成数组方便处理
        $decodedArr = (array)$decoded;
        
        // 校验签发者
        if ($decodedArr['iss'] !== $expectedIss) {
            return false;
        }
        
        // 校验受众,支持单aud和多aud场景
        $aud = $decodedArr['aud'] ?? '';
        $audIsValid = false;
        if (is_string($aud) && in_array($aud, $allowedAud)) {
            $audIsValid = true;
        } elseif (is_array($aud)) {
            foreach ($aud as $item) {
                if (in_array($item, $allowedAud)) {
                    $audIsValid = true;
                    break;
                }
            }
        }
        if (!$audIsValid) {
            return false;
        }
        
        // 如需校验scope可以在这里加逻辑
        // $expectedScopes = ['openid', 'profile'];
        // $tokenScopes = explode(' ', $decodedArr['scope'] ?? '');
        // if (!count(array_intersect($expectedScopes, $tokenScopes))) return false;
        
        return $decodedArr;
    } catch (ExpiredException $e) {
        // token已过期
        return false;
    } catch (BeforeValidException $e) {
        // token尚未生效
        return false;
    } catch (SignatureInvalidException $e) {
        // 签名校验失败,token被篡改
        return false;
    } catch (Exception $e) {
        // 其他错误
        return false;
    }
}

// 使用示例
$token = '你要验证的id token或者access token';
$tokenInfo = validateKeycloakToken($token, $keycloakPublicKey, $expectedIss, $allowedAud);
if ($tokenInfo) {
    // 验证通过,处理业务逻辑
    var_dump($tokenInfo);
} else {
    // 验证失败,返回401
    http_response_code(401);
    exit('Token invalid');
}
注意事项
  • 不要使用HS256等对称加密算法签名token,此类算法需要共享密钥,安全性远低于RS256非对称方案
  • 受控环境下如果Keycloak有签名密钥轮转操作,同步更新中间件内的公钥即可,轮转频率低,维护成本很低

内容的提问来源于stack exchange,提问作者Rammboss

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 15:18:03