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

PHP中如何验证JWT令牌并提取声明?Azure B2C集成问题排查

问题根因排查

重定向到login.php的核心原因

  • Azure AD B2C完成登录后的重定向是GET请求,默认不会携带Authorization请求头,你的代码第一判断逻辑就是该头不存在直接跳转登录页,必然会触发重定向。B2C返回的ID Token/Access Token默认放在URL的id_token/access_token查询参数中,需要从$_GET全局变量读取,而非请求头。
  • 代码存在低级拼写错误:你定义的token变量是$retrievedToken,调用JWT::decode时用的是$retrieveToken,变量名少了末尾的d,会触发未定义变量错误,导致后续逻辑中断。
  • 签名算法与密钥规则不匹配:Azure B2C默认使用RS256非对称加密算法签名JWT,你的代码硬编码了HS256和自定义密钥,完全不符合B2C的签名规则,就算拿到正确token也会验证失败。

密钥疑问解答

JWT头部的kid(密钥ID)是B2C系统内部生成的,用于标识签名所用的密钥对,和你脚本里写的自定义密钥没有任何关系。B2C用私钥对JWT签名,你需要从B2C的公开JWKS(JSON Web密钥集)中拿到对应kid的公钥,才能完成签名验证。


修复后的可运行代码

require_once "/home/mydirectory/vendor/autoload.php";
use Firebase\JWT\JWT;
use Firebase\JWT\Key;

// 1. 从B2C回调的URL参数中获取ID Token
if (!isset($_GET['id_token'])) {
    header('Location: login.php');
    exit;
}
$retrievedToken = $_GET['id_token'];

// 2. 替换为你自己的B2C配置参数
$issuer = 'https://example.org/lettersnumbers/v2.0/'; // 你的B2C issuer地址
$tenantName = '你的B2C租户名称';
$policyName = '你的用户流策略名,例如B2C_1_signinsignup';

// 3. 获取B2C公钥列表(生产环境建议对公钥做缓存,避免每次请求拉取)
$jwksUrl = "https://{$tenantName}.b2clogin.com/{$tenantName}.onmicrosoft.com/{$policyName}/discovery/v2.0/keys";
$jwks = json_decode(file_get_contents($jwksUrl), true);
$keys = [];
foreach ($jwks['keys'] as $k) {
    $publicKey = openssl_pkey_get_public("-----BEGIN PUBLIC KEY-----\n" . wordwrap($k['x5c'][0], 64, "\n", true) . "\n-----END PUBLIC KEY-----");
    $keys[$k['kid']] = new Key($publicKey, $k['alg']);
}

try {
    // 4. 自动匹配对应kid的公钥解码验证JWT
    $token = JWT::decode($retrievedToken, $keys);
    $now = new DateTimeImmutable();
    
    // 5. 额外验证发行方、有效期等字段
    if ($token->iss !== $issuer || $token->nbf > $now->getTimestamp() || $token->exp < $now->getTimestamp()) {
        header('HTTP/1.1 401 Unauthorized');
        exit;
    }
    
    // 6. 提取目标字段
    $firstName = $token->first_name;
} catch (Exception $e) {
    // 验证失败跳转登录
    header('Location: login.php');
    exit;
}

补充说明

你原本的.htaccess配置作用是将Authorization头透传给PHP,仅在请求主动携带该头的场景生效,B2C回调场景不需要用到该配置,可以保留用于后续前后端分离的请求验证。生产环境建议首次拿到token后存入session,避免token长期暴露在URL中。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 13:15:02