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

.NET MVC中通过私钥生成SAML断言的技术求助

在.NET MVC中生成SuccessFactors OAuth认证用的Base64编码SAML断言

核心要求(来自SuccessFactors官方规范)

SuccessFactors OAuth认证所需的SAML断言必须满足以下格式要求:

  • Issuer:取值为你的clientid
  • Subject:包含NameID元素,值为指定的userid
  • Conditions:设置断言生效时间(NotBefore)和过期时间(NotOnOrAfter),过期时间由expireInMinutes参数计算得出
  • AudienceRestriction:Audience值为提供的tokenurl
  • Signature:使用PEM格式私钥对断言进行XML签名,签名算法必须为SHA256-RSA

实现步骤与代码示例

1. 安装依赖NuGet包

确保项目中引用以下包:

Install-Package System.IdentityModel.Tokens.Jwt
Install-Package System.Security.Cryptography.Xml

2. 加载PEM私钥

将PEM格式的私钥转换为RSACryptoServiceProvider实例:

private static RSACryptoServiceProvider LoadPemPrivateKey(string pemFilePath)
{
    var pemContent = File.ReadAllText(pemFilePath);
    // 移除PEM头、尾及换行符
    var cleanedPem = pemContent
        .Replace("-----BEGIN PRIVATE KEY-----", "")
        .Replace("-----END PRIVATE KEY-----", "")
        .Replace("\r\n", "")
        .Replace("\n", "");

    var privateKeyBytes = Convert.FromBase64String(cleanedPem);
    var rsa = new RSACryptoServiceProvider();
    rsa.ImportPkcs8PrivateKey(privateKeyBytes, out _);
    return rsa;
}

注:如果你的私钥是PKCS#1格式(开头为-----BEGIN RSA PRIVATE KEY-----),请改用ImportFromPem方法加载。

3. 构建SAML断言XML结构

生成符合SuccessFactors要求的SAML断言基础XML:

private static XmlDocument BuildSamlAssertionXml(string userId, string clientId, string tokenUrl, int expireInMinutes)
{
    var assertionId = "_" + Guid.NewGuid();
    var utcNow = DateTime.UtcNow;
    var issueInstant = utcNow.ToString("yyyy-MM-ddTHH:mm:ssZ");
    var notOnOrAfter = utcNow.AddMinutes(expireInMinutes).ToString("yyyy-MM-ddTHH:mm:ssZ");

    var xmlDoc = new XmlDocument();
    xmlDoc.LoadXml($@"
<saml:Assertion xmlns:saml=""urn:oasis:names:tc:SAML:2.0:assertion"" ID=""{assertionId}"" IssueInstant=""{issueInstant}"" Version=""2.0"">
    <saml:Issuer>{clientId}</saml:Issuer>
    <saml:Subject>
        <saml:NameID Format=""urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"">{userId}</saml:NameID>
        <saml:SubjectConfirmation Method=""urn:oasis:names:tc:SAML:2.0:cm:bearer"">
            <saml:SubjectConfirmationData NotOnOrAfter=""{notOnOrAfter}"" Recipient=""{tokenUrl}"" />
        </saml:SubjectConfirmation>
    </saml:Subject>
    <saml:Conditions NotBefore=""{issueInstant}"" NotOnOrAfter=""{notOnOrAfter}"">
        <saml:AudienceRestriction>
            <saml:Audience>{tokenUrl}</saml:Audience>
        </saml:AudienceRestriction>
    </saml:Conditions>
</saml:Assertion>");

    return xmlDoc;
}

4. 对SAML断言进行签名

使用私钥对XML断言进行数字签名:

private static XmlDocument SignSamlAssertion(XmlDocument samlXml, RSACryptoServiceProvider privateKey)
{
    var signedXml = new SignedXml(samlXml);
    signedXml.SigningKey = privateKey;

    // 指定要签名的断言节点
    var reference = new Reference($"#{samlXml.DocumentElement.GetAttribute("ID")}");
    reference.AddTransform(new XmlDsigEnvelopedSignatureTransform());
    reference.AddTransform(new XmlDsigExcC14NTransform());
    reference.DigestMethod = SignedXml.XmlDsigSHA256Url;
    signedXml.AddReference(reference);

    // 添加密钥信息(可选,但部分环境要求)
    var keyInfo = new KeyInfo();
    keyInfo.AddClause(new RSAKeyValue(privateKey));
    signedXml.KeyInfo = keyInfo;

    // 生成签名并插入到XML中
    signedXml.ComputeSignature();
    var signatureNode = signedXml.GetXml();
    samlXml.DocumentElement.AppendChild(samlXml.ImportNode(signatureNode, true));

    return samlXml;
}

5. 生成Base64编码的断言

将签名后的XML转换为无换行的Base64字符串:

public static string GenerateBase64SamlAssertion(string pemFilePath, string userId, string clientId, string tokenUrl, int expireInMinutes)
{
    using var privateKey = LoadPemPrivateKey(pemFilePath);
    var samlXml = BuildSamlAssertionXml(userId, clientId, tokenUrl, expireInMinutes);
    var signedSamlXml = SignSamlAssertion(samlXml, privateKey);

    // 转换为UTF-8字节数组后Base64编码,移除所有换行符
    var xmlBytes = Encoding.UTF8.GetBytes(signedSamlXml.OuterXml);
    return Convert.ToBase64String(xmlBytes).Replace("\r\n", "").Replace("\n", "");
}

关键注意事项

  • 所有时间必须使用UTC时间,否则SuccessFactors会判定断言无效
  • 确保PEM私钥无密码保护,若有密码需额外处理解密逻辑
  • 生成的Base64字符串不能包含任何换行或空格,否则认证请求会失败
  • 若遇到签名验证错误,检查私钥格式是否正确,签名算法是否为SHA256-RSA

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 22:43:20