PHP7.3对接Maskinporten生成含x5c参数的JWT证书问题
解决PHP7.3下Maskinporten JWT生成及证书读取问题
一、先解决public_keys.txt证书读取失败问题
openssl系列函数调用失败,核心原因是证书格式不符合PHP预期,按以下步骤排查修复:
检查并修复证书格式
- 打开
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 - 若文件中包含多个证书,先拆分每个证书为单独的文件,再逐个处理。
- 打开
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:
从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;构建JWT头部
头部必须指定alg: RS256(Maskinporten仅支持该算法),并包含完整的x5c证书链:$header = [ 'alg' => 'RS256', 'x5c' => $x5cChain ]; // 编码并替换URL不安全字符 $encodedHeader = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode(json_encode($header)));构建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)));签名生成最终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
相关产品推荐
相关产品推荐

