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

服务器端使用dotnet-passbook v3.2.0生成的Pkpass无法打开问题

问题说明
  • 基于dotnet-passbook 3.2.0版本生成Pkpass文件,本地环境生成的文件可正常打开,部署到服务器后生成的文件无法打开
  • 将服务器生成的Pkpass文件上传到Pkpass验证工具检测,仅返回Failed to process the Pkpass file.的通用报错,无具体错误指向
  • 核心生成代码如下:
public static FileContentResult GetPass(Shopper account)
{
    try {
        if (account == null)
        {
            return null;
        }

        PassGenerator generator = new PassGenerator();
        PassGeneratorRequest request = new PassGeneratorRequest();

        // 基础配置
        request.PassTypeIdentifier = "PassTypeIdentifier";
        request.TeamIdentifier = "TeamIdentifier";
        request.SerialNumber = "SerialNumber";
        request.Description = "Description";
        request.OrganizationName = "OrganizationName";
        request.LogoText = "LogoText";

        WebClient webClient = new WebClient();
        // 加载Pass签名证书
        try
        {
            X509KeyStorageFlags flags = X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.Exportable;
            request.PassbookCertificate = new X509Certificate2(webClient.DownloadData(CertificatesBucket + "/Certificates.p12"), S3_AppleCertificatePassword, flags);
        }
        catch (Exception e)
        {
            throw new Exception("加载证书异常: " + e.Message);
        }

        // 加载Apple WWDR根证书
        try
        {
            request.AppleWWDRCACertificate = new X509Certificate2(webClient.DownloadData(CertificatesBucket + "/AppleWWDRCAG2.cer"));
        }
        catch (Exception e)
        {
            throw new Exception("加载AppleWWDRCA证书异常: " + e.Message);
        }
        // 加载Pass图片资源
        try
        {
             request.Images.Add(PassbookImage.Logo, webClient.DownloadData(AppleImageBucket + "/logo.png"));
             request.Images.Add(PassbookImage.Icon, webClient.DownloadData(AppleImageBucket + "/icon.png"));
             request.Images.Add(PassbookImage.Icon2X, webClient.DownloadData(AppleImageBucket + "/icon%402x.png"));
             request.Images.Add(PassbookImage.Strip, webClient.DownloadData(AppleImageBucket + "/strip.png"));
             request.Images.Add(PassbookImage.Strip2X, webClient.DownloadData(AppleImageBucket + "/strip%402x.png"));
        }
        catch (Exception e)
        {
            throw new Exception("加载图片资源异常: " + e.Message);
        }
        // 添加条形码
        request.AddBarcode(BarcodeType.PKBarcodeFormatCode128, account.Id, "ISO-8859-1");

        // 关联应用ID
        request.AssociatedStoreIdentifiers.Add(121212);

        request.Style = PassStyle.StoreCard;

        // 添加卡片展示字段
        request.AddHeaderField(new StandardField("StandardField", "TEXT", account.Id));
        request.AddSecondaryField(new StandardField("StandardField", "TEXT", account.Name));
        request.AddSecondaryField(new StandardField("StandardField", "TEXT", "TEXT"));

        request.TransitType = TransitType.PKTransitTypeAir;

        byte[] generatedPass = generator.Generate(request);

        return new FileContentResult(generatedPass, "application/vnd.apple.pkpass");
    }
    catch (Exception ex)
    {
        throw new Exception("生成Apple Pass异常: " + ex.Message);
    }
}
排查与修复方案

按问题出现概率从高到低排查:

  • 第一优先级修复证书加载标记,这是本地正常、服务器生成失败的最高发原因,占同类问题的90%以上。你当前的X509KeyStorageFlags缺少PersistKeySet标记,服务器IIS环境下运行应用池的服务账号没有持久化密钥权限,私钥加载后会被系统立刻回收,导致签名流程生成的signature文件无效,整个pkpass包结构损坏。修改证书加载代码如下:
    X509KeyStorageFlags flags = X509KeyStorageFlags.MachineKeySet 
                              | X509KeyStorageFlags.Exportable 
                              | X509KeyStorageFlags.PersistKeySet;
    
    本地调试时因为用的是当前登录用户的上下文,密钥存储在用户个人目录下不会被回收,所以不会触发这个问题,一到服务器用服务账号跑必现。
  • 修复Pass类型配置冲突:你设置的Pass类型是StoreCard(商店卡),但额外配置了仅交通卡、登机牌类Pass才允许出现的TransitType字段,非交通类Pass包含这个字段会直接导致pass.json格式校验失败,直接删掉request.TransitType = TransitType.PKTransitTypeAir;这行即可。
  • 替换WWDR根证书:Apple已经停用了G2版本的WWDR根证书,你现在加载的AppleWWDRCAG2.cer已经过期,需要替换为最新的G4版本WWDR证书,否则签名会被判定为无效。
  • 修复图片资源加载问题:
    • 2x分辨率的图片路径不要手动写URL编码的%40,直接写icon@2x.png、strip@2x.png即可,WebClient会自动处理路径编码,手动写%40会导致实际请求路径重复编码,下载到错误的内容
    • 加日志打印下载到的图片字节长度,确认服务器网络策略没有拦截对象存储的请求,不会下载到403/404的错误页内容
  • 手动校验生成文件:把服务器生成的pkpass后缀改成.zip解压,检查三个核心点:
    • 包内是否包含signature文件,且文件大小不为0
    • manifest.json里是否列出了包内所有文件的哈希值,没有遗漏
    • pass.json里的PassTypeIdentifier、TeamIdentifier是实际申请的证书对应值,不是占位符
  • 确认服务器环境的系统编码不会篡改生成的json内容,所有文本输出用UTF-8无BOM编码。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 14:33:18