.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
相关产品推荐
相关产品推荐

