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

.NET 8 Native AOT下SignedXml冲突及License验证失败解决咨询

解决方案

一、解决IL3050错误(SignedXml与Native AOT兼容问题)

System.Security.Cryptography.Xml.SignedXml依赖的XmlDsigXsltTransform需要动态代码生成,而Native AOT不支持动态代码,可通过以下两种方式处理:

1. 移除不必要的XSLT转换(推荐)

如果你的License签名流程未使用XSLT转换,可自定义SignedXml子类,跳过对XmlDsigXsltTransform的支持:

public class AotCompatibleSignedXml : SignedXml
{
    public AotCompatibleSignedXml(XmlDocument doc) : base(doc) { }

    protected override Transform CreateTransform(string transformUri)
    {
        // 跳过XSLT转换,避免触发动态代码
        if (transformUri == SignedXml.XmlDsigXsltTransformUrl)
        {
            throw new NotSupportedException("XSLT transforms are not supported in AOT");
        }
        return base.CreateTransform(transformUri);
    }
}

验证时使用该子类替代原生SignedXml,同时确保License生成环节未添加XSLT转换。

2. 允许动态代码(不推荐)

若必须保留XSLT转换,可在项目文件中添加配置开启动态代码支持,但会损失AOT的部分优势(如启动速度、封闭性):

<PropertyGroup>
    <DynamicCodeSupport>true</DynamicCodeSupport>
</PropertyGroup>

二、解决自行实现VerifyHash/VerifyData返回false的问题

直接使用SignedInfo.OuterXml获取字节流不符合XML-DSIG规范,因为SignedXml计算签名时采用**独占规范XML(Exclusive Canonical XML)**序列化,而OuterXml输出格式与该序列化结果不一致,导致哈希不匹配。正确做法是对SignedInfo节点进行规范XML序列化:

XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(nodeList[0].OuterXml);

XmlNamespaceManager nsManager = GetNamespaceManager(xmlDoc);
XmlNode signedInfoNode = xmlDoc.SelectSingleNode("//ds:SignedInfo", nsManager);

// 对SignedInfo节点执行独占规范XML序列化
var canonicalizer = new XmlDsigExcC14NTransform();
canonicalizer.LoadInput(signedInfoNode);
byte[] signedInfoBytes;
using (var ms = new MemoryStream())
{
    canonicalizer.GetOutput(ms);
    signedInfoBytes = ms.ToArray();
}

// 获取签名值
XmlNode signatureValueNode = xmlDoc.SelectSingleNode("//ds:SignatureValue", nsManager);
byte[] signatureValue = Convert.FromBase64String(signatureValueNode.InnerText);

// 使用RSA公钥验证
using (var rsa = RSA.Create())
{
    rsa.ImportFromPem(yourPublicKeyPem); // 替换为你的公钥内容
    bool isValid = rsa.VerifyData(signedInfoBytes, signatureValue, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1);
    return isValid;
}

若签名使用普通C14N规范XML,需替换为XmlDsigC14NTransform。

三、替代License验证方案(更适配Native AOT)

若不想处理SignedXml的AOT兼容问题,可改用以下轻量、AOT友好的方案:

1. 自定义二进制License格式

将License核心信息(用户ID、有效期、机器标识等)序列化为二进制(推荐用System.Text.Json序列化),再用RSA对数据签名,验证时反序列化并校验签名:

// 定义License数据结构
public class LicenseData
{
    public string UserId { get; set; }
    public DateTime ExpireDate { get; set; }
    public string MachineId { get; set; }
}

// 生成License
var licenseData = new LicenseData
{
    UserId = "user123",
    ExpireDate = DateTime.Now.AddYears(1),
    MachineId = "abc123"
};
byte[] dataBytes = JsonSerializer.SerializeToUtf8Bytes(licenseData);
byte[] signature = rsa.SignData(dataBytes, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
// 将dataBytes和signature组合写入License文件(例如先写数据长度,再写数据,最后写签名)

// 验证License
// 读取License文件,拆分dataBytes和signature
var licenseData = JsonSerializer.Deserialize<LicenseData>(dataBytes);
bool isValid = rsa.VerifyData(dataBytes, signature, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
// 额外校验有效期、机器标识等逻辑

2. 使用JWT(JSON Web Token)

JWT是标准化令牌格式,System.IdentityModel.Tokens.Jwt库兼容AOT,可将License信息存入JWT Payload,用RSA签名,验证时直接校验签名与Payload内容:

// 生成JWT License
var claims = new List<Claim>
{
    new Claim("userId", "user123"),
    new Claim("exp", DateTimeOffset.Now.AddYears(1).ToUnixTimeSeconds().ToString())
};
var token = new JwtSecurityToken(
    issuer: "yourCompany",
    claims: claims,
    expires: DateTime.Now.AddYears(1),
    signingCredentials: new SigningCredentials(new RsaSecurityKey(rsa), SecurityAlgorithms.RsaSha256)
);
string license = new JwtSecurityTokenHandler().WriteToken(token);

// 验证JWT License
var handler = new JwtSecurityTokenHandler();
var validationParameters = new TokenValidationParameters
{
    ValidateIssuer = true,
    ValidIssuer = "yourCompany",
    ValidateLifetime = true,
    ValidateAudience = false,
    IssuerSigningKey = new RsaSecurityKey(publicRsa)
};
try
{
    handler.ValidateToken(license, validationParameters, out _);
    return true;
}
catch
{
    return false;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 13:10:10