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

.NET中基于RSA的简易签名令牌认证机制实现疑问

问题分析与解决方案

你现在的核心问题是混淆了RSA签名和加密的概念——SignData生成的是签名,不是加密后的令牌,签名无法还原出原始的JSON令牌内容,所以接收方拿到签名后既没法“解密”出issuer和过期时间,也没法验证原始数据的合法性。

一、修正现有逻辑:同时传递原始令牌与签名

你需要把原始JSON令牌和签名一起发送给微服务Y,因为签名仅用于证明令牌未被篡改,接收方必须拿到原始令牌才能校验字段。

发送方代码调整

using (var rsa = RSA.Create())
{
    rsa.ImportFromPem(PrivateKey);

    // 生成原始JSON令牌
    var rawToken = AuthMaintenanceToken.CreateToken();
    byte[] tokenBytes = Encoding.UTF8.GetBytes(rawToken);

    // 对原始令牌生成签名
    byte[] signature = rsa.SignData(tokenBytes, HashAlgorithmName.SHA512, RSASignaturePadding.Pkcs1);
    string base64Signature = Convert.ToBase64String(signature);

    // 拼接原始令牌(Base64编码)与签名(Base64编码),用.分隔
    string base64Token = Convert.ToBase64String(tokenBytes);
    return $"{base64Token}.{base64Signature}";
}

将拼接后的字符串放入请求头xyx中发送。

接收方验证逻辑

// 从请求头获取令牌字符串
string authHeader = Request.Headers["xyx"];
if (string.IsNullOrEmpty(authHeader))
{
    return Unauthorized();
}

// 拆分原始令牌与签名
string[] parts = authHeader.Split('.');
if (parts.Length != 2)
{
    return Unauthorized();
}

try
{
    // 解码原始令牌和签名
    byte[] tokenBytes = Convert.FromBase64String(parts[0]);
    string rawToken = Encoding.UTF8.GetString(tokenBytes);
    byte[] signatureBytes = Convert.FromBase64String(parts[1]);

    // 用公钥验证签名有效性
    using (var rsa = RSA.Create())
    {
        rsa.ImportFromPem(PublicKey);
        bool isSignatureValid = rsa.VerifyData(tokenBytes, signatureBytes, HashAlgorithmName.SHA512, RSASignaturePadding.Pkcs1);
        if (!isSignatureValid)
        {
            return Unauthorized();
        }
    }

    // 解析令牌并校验字段
    var token = JsonSerializer.Deserialize<AuthMaintenanceToken>(rawToken);
    if (token == null 
        || token.Issuer != "微服务X的唯一标识" 
        || token.ExpirationTime < DateTime.UtcNow)
    {
        return Unauthorized();
    }

    // 验证通过,处理请求
    return Ok();
}
catch (Exception)
{
    // 任何解码/验证失败都拒绝请求
    return Unauthorized();
}

二、更规范的替代方案:使用标准JWT(推荐)

自己拼接令牌和签名容易出错,推荐直接使用标准JWT(JSON Web Token),它原生支持RSA签名(JWS),且有成熟库简化开发。

发送方生成JWT

using System.IdentityModel.Tokens.Jwt;
using Microsoft.IdentityModel.Tokens;

var securityKey = new RsaSecurityKey(RSA.Create().ImportFromPem(PrivateKey));
var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.RsaSha512);

var tokenHandler = new JwtSecurityTokenHandler();
var tokenDescriptor = new SecurityTokenDescriptor
{
    Issuer = "微服务X的唯一标识",
    Expires = DateTime.UtcNow.AddHours(1), // 设置过期时间
    SigningCredentials = credentials
};

var jwtToken = tokenHandler.CreateJwtSecurityToken(tokenDescriptor);
string token = tokenHandler.WriteToken(jwtToken);

// 将token放入请求头"xyx"(通常格式为"Bearer {token}")发送

接收方验证JWT

using System.IdentityModel.Tokens.Jwt;
using Microsoft.IdentityModel.Tokens;

string authHeader = Request.Headers["xyx"];
if (string.IsNullOrEmpty(authHeader) || !authHeader.StartsWith("Bearer "))
{
    return Unauthorized();
}

string token = authHeader.Substring(7);

var validationParameters = new TokenValidationParameters
{
    ValidIssuer = "微服务X的唯一标识",
    ValidateIssuer = true,
    ValidateLifetime = true, // 自动验证过期时间
    IssuerSigningKey = new RsaSecurityKey(RSA.Create().ImportFromPem(PublicKey)),
    ValidateIssuerSigningKey = true
};

try
{
    var tokenHandler = new JwtSecurityTokenHandler();
    tokenHandler.ValidateToken(token, validationParameters, out SecurityToken validatedToken);
    
    // 验证通过,处理请求
    return Ok();
}
catch (Exception)
{
    return Unauthorized();
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 12:35:40