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

C#参照Java示例生成Security Event Token(SET)实现方法

C# 生成符合规范的安全事件令牌(SET)实现方案

SET本质是带特定头、载荷结构,使用指定算法签名的JWT,对齐你提供的Java示例核心要求如下:

  • 签名算法固定使用PS512(RSASSA-PSS + SHA512)
  • JWT头的typ字段必须为secevent+jwt,同时携带kid(公钥唯一标识)和alg字段
  • 载荷字段和Java示例完全匹配

下面分别给出使用jose-jwt库、以及微软官方JWT库的两种实现方式。


方案1:使用jose-jwt实现(推荐,逻辑更简洁)

首先通过Nuget安装依赖:

dotnet add package jose-jwt

核心实现代码:

using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using Jose;

public string GenerateSET(
    string issuer,
    string subject,
    string transactionId,
    string eventTargetUrl,
    string publicKeyId,
    RSA rsaPrivateKey)
{
    // 构造载荷,和Java示例字段一一对应
    var utcNow = DateTimeOffset.UtcNow;
    var payload = new Dictionary<string, object>
    {
        ["iss"] = issuer,
        ["iat"] = utcNow.ToUnixTimeSeconds(), // 秒级UTC时间戳,和Java默认JWT iat格式一致
        ["jti"] = Guid.NewGuid().ToString(),
        ["sub"] = subject,
        ["events"] = new Dictionary<string, object>
        {
            // 键为事件投递目标URL,值为空对象,和Java Map.of(event, Map.of())逻辑一致
            [eventTargetUrl] = new Dictionary<string, object>()
        },
        ["txn"] = transactionId
    };

    // 构造JWT头
    var headers = new Dictionary<string, object>
    {
        ["typ"] = "secevent+jwt",
        ["kid"] = publicKeyId,
        ["alg"] = "PS512"
    };

    // 签名并序列化为Base64字符串
    return JWT.Encode(
        payload: payload,
        key: rsaPrivateKey,
        algorithm: JwsAlgorithm.PS512,
        extraHeaders: headers);
}

RSA私钥加载示例(支持PEM格式):

// 从PEM文件加载私钥
string privateKeyText = File.ReadAllText("path/to/your/rsa_private.pem");
RSA rsaKey = RSA.Create();
rsaKey.ImportFromPem(privateKeyText);
// 如果是加密的PEM私钥,调用ImportFromEncryptedPem方法传入密码即可

方案2:使用微软官方System.IdentityModel.Tokens.Jwt实现

如果不想用第三方的jose-jwt,可以用微软官方的JWT库,先安装依赖:

dotnet add package System.IdentityModel.Tokens.Jwt

核心实现代码:

using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;

public string GenerateSETWithMsLib(
    string issuer,
    string subject,
    string transactionId,
    string eventTargetUrl,
    string publicKeyId,
    RSA rsaPrivateKey)
{
    var utcNow = DateTime.UtcNow;
    var securityKey = new RsaSecurityKey(rsaPrivateKey) { KeyId = publicKeyId };
    // 指定PS512签名算法
    var signingCreds = new SigningCredentials(securityKey, SecurityAlgorithms.RsaSsaPssSha512);

    var tokenHandler = new JwtSecurityTokenHandler();
    var token = new JwtSecurityToken(
        issuer: issuer,
        claims: new List<System.Security.Claims.Claim>
        {
            new System.Security.Claims.Claim("sub", subject),
            new System.Security.Claims.Claim("jti", Guid.NewGuid().ToString()),
            new System.Security.Claims.Claim("txn", transactionId)
        },
        signingCredentials: signingCreds,
        issuedAt: utcNow
    );

    // 覆盖默认typ头,修正为SET要求的固定值
    token.Header["typ"] = "secevent+jwt";
    // 修正iat为秒级时间戳,补充events字段
    token.Payload["iat"] = new DateTimeOffset(utcNow).ToUnixTimeSeconds();
    token.Payload["events"] = new Dictionary<string, object>
    {
        [eventTargetUrl] = new Dictionary<string, object>()
    };

    return tokenHandler.WriteToken(token);
}

注意事项

  • 不要使用普通RS512算法签名,必须使用PS512,二者填充模式不同,签名结果不兼容
  • typ头必须严格设置为secevent+jwt,不能使用默认的JWT值,否则接收方会校验失败
  • iat字段必须是UTC时区的秒级Unix时间戳,不要使用本地时间、不要传毫秒级时间戳
  • events字段结构必须为「URL作为键、空对象作为值」的嵌套对象,不要写错格式
  • 生成后可以把令牌字符串做Base64解码,核对头、载荷字段是否和Java示例预期完全一致,再验证签名有效性即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.03 08:15:27