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

PHP7.3对接Maskinporten生成含x5c参数的JWT证书问题

解决PHP7.3下Maskinporten JWT生成及证书读取问题

一、先解决public_keys.txt证书读取失败问题

openssl系列函数调用失败,核心原因是证书格式不符合PHP预期,按以下步骤排查修复:

  1. 检查并修复证书格式

    • 打开public_keys.txt,确认每个证书包含完整的PEM头尾:-----BEGIN CERTIFICATE-----和-----END CERTIFICATE-----
    • 检查证书内容的base64编码是否按每64字符换行(部分导出的证书可能缺失换行,导致PHP无法识别)
    • 如果证书是DER二进制格式(无PEM头尾),先通过命令行转成PEM格式:
      openssl x509 -inform der -in your-cert-file -out converted-cert.pem
      
    • 若文件中包含多个证书,先拆分每个证书为单独的文件,再逐个处理。
  2. PHP7.3下读取证书的正确代码
    读取单个证书时,先处理格式问题再调用openssl函数:

    // 读取单个证书文件内容
    $certContent = file_get_contents('path/to/single-cert.pem');
    // 统一换行格式,修复可能的格式错误
    $certContent = preg_replace('/\r\n?/', "\n", $certContent);
    
    $cert = openssl_x509_read($certContent);
    if (!$cert) {
        // 打印openssl错误信息排查问题
        while ($error = openssl_error_string()) {
            echo $error . "\n";
        }
        exit;
    }
    
    // 解析证书信息
    $certInfo = openssl_x509_parse($cert);
    print_r($certInfo);
    
    // 释放资源
    openssl_x509_free($cert);
    

二、生成符合Maskinporten要求的JWT

解决证书读取问题后,按以下流程生成带x5c参数的JWT:

  1. 从p12文件提取私钥与证书
    从sign-certificate.p12中提取用于签名的RSA私钥,以及证书链:

    $p12Content = file_get_contents('sign-certificate.p12');
    $p12Password = '你的p12激活码密码';
    $certData = [];
    
    if (!openssl_pkcs12_read($p12Content, $certData, $p12Password)) {
        while ($error = openssl_error_string()) {
            echo $error . "\n";
        }
        exit;
    }
    
    $privateKey = $certData['pkey'];
    // 初始化x5c证书链,先加入用户证书(去掉PEM头尾和换行)
    $x5cChain = [
        str_replace(["-----BEGIN CERTIFICATE-----", "-----END CERTIFICATE-----", "\n"], '', $certData['cert'])
    ];
    
    // 读取并添加public_keys.txt中的中间证书、根证书(顺序:用户证书→中间证书→根证书)
    $middleCert = file_get_contents('path/to/middle-cert.pem');
    $middleCertClean = str_replace(["-----BEGIN CERTIFICATE-----", "-----END CERTIFICATE-----", "\n"], '', $middleCert);
    $x5cChain[] = $middleCertClean;
    
    $rootCert = file_get_contents('path/to/root-cert.pem');
    $rootCertClean = str_replace(["-----BEGIN CERTIFICATE-----", "-----END CERTIFICATE-----", "\n"], '', $rootCert);
    $x5cChain[] = $rootCertClean;
    
  2. 构建JWT头部
    头部必须指定alg: RS256(Maskinporten仅支持该算法),并包含完整的x5c证书链:

    $header = [
        'alg' => 'RS256',
        'x5c' => $x5cChain
    ];
    // 编码并替换URL不安全字符
    $encodedHeader = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode(json_encode($header)));
    
  3. 构建JWT Payload
    按Maskinporten要求设置必要字段:

    $payload = [
        'iss' => '你的客户端ID',
        'aud' => 'https://maskinporten.no/token',
        'exp' => time() + 3600, // 过期时间最长1小时
        'scope' => '你的目标API权限范围',
        'sub' => '可选的主体标识'
    ];
    $encodedPayload = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode(json_encode($payload)));
    
  4. 签名生成最终JWT
    用私钥对头部与Payload的组合进行SHA256-RSA签名:

    $dataToSign = $encodedHeader . '.' . $encodedPayload;
    $signature = '';
    openssl_sign($dataToSign, $signature, $privateKey, OPENSSL_ALGO_SHA256);
    
    $encodedSignature = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($signature));
    $jwt = $encodedHeader . '.' . $encodedPayload . '.' . $encodedSignature;
    
    echo $jwt;
    

三、PHP7.3特殊处理

  • openssl_x509_verify在PHP7.3中不可用,可通过命令行验证证书链:
    openssl verify -CAfile root-cert.pem -untrusted intermediate-cert.pem user-cert.pem
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 02:31:14