.NET 3.5项目中如何使用System.IdentityModel.Tokens.Jwt 5.2.1验证JWT令牌?
在.NET Framework 3.5中验证JWT令牌的解决方案
你遇到的问题很典型:你之前在.NET Framework 4.5.2中用的Microsoft.IdentityModel.Tokens和JwtSecurityTokenHandler这套官方JWT组件,是从.NET Framework 4.5才开始引入的,.NET 3.5根本没有这些类库,直接移植代码肯定会报错。下面给你两种可行的解决思路:
方案一:使用兼容.NET 3.5的第三方JWT库
最省心的方式是用第三方库,比如JWT.NET(旧版本支持.NET 3.5)。你需要找支持.NET 3.5的版本,比如v3.x系列(新版本已经不再支持3.5了)。
安装步骤
如果你用NuGet包管理器,搜索JWT并选择版本3.0.2(这个版本明确支持.NET 3.5);如果是手动引用,去下载对应的DLL文件。
验证令牌的示例代码
using System; using System.Collections.Generic; using JWT; using JWT.Algorithms; using JWT.Serializers; namespace TokenValidator { public class TokenValidationHelper { public static bool ValidateToken(string token, string secretKey) { try { var serializer = new JsonNetSerializer(); var provider = new UtcDateTimeProvider(); var validator = new JwtValidator(serializer, provider); var urlEncoder = new JwtBase64UrlEncoder(); var algorithm = new HMACSHA256Algorithm(); // 根据你的令牌签名算法调整,比如HS512等 var decoder = new JwtDecoder(serializer, validator, urlEncoder, algorithm); // 解码并验证令牌,验证通过会返回Payload,失败则抛出异常 var payload = decoder.DecodeToObject<Dictionary<string, object>>(token, secretKey, verify: true); // 这里可以额外验证Payload里的自定义字段,比如exp(过期时间)、iss(签发者)等 if (payload.ContainsKey("exp")) { var expTime = UnixTimeStampToDateTime(Convert.ToDouble(payload["exp"])); if (expTime < DateTime.UtcNow) { return false; } } return true; } catch (TokenExpiredException) { // 令牌过期 return false; } catch (SignatureVerificationException) { // 签名验证失败 return false; } catch (Exception) { // 其他错误 return false; } } private static DateTime UnixTimeStampToDateTime(double unixTimeStamp) { var dtDateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc); dtDateTime = dtDateTime.AddSeconds(unixTimeStamp).ToLocalTime(); return dtDateTime; } } }
方案二:手动解析并验证JWT令牌
如果不想依赖第三方库,你可以手动解析JWT的结构,因为JWT本质是由Base64Url编码的三部分(Header、Payload、Signature)组成的字符串,用.分隔。
手动验证的核心步骤
- 拆分令牌为Header、Payload、Signature三部分
- 对Header和Payload进行Base64Url解码,获取内容
- 重新拼接Header和Payload(用
.连接),然后用对应的签名算法(比如HMACSHA256)结合密钥计算签名,和原令牌的Signature对比 - 额外验证Payload里的过期时间、签发者等自定义字段
示例代码(HS256签名算法为例)
using System; using System.Text; using System.Security.Cryptography; using System.Web.Script.Serialization; // 需要引用System.Web.Extensions.dll namespace TokenValidator { public class ManualTokenValidator { public static bool ValidateToken(string token, string secretKey) { var parts = token.Split('.'); if (parts.Length != 3) return false; var header = parts[0]; var payload = parts[1]; var signature = parts[2]; // 验证签名 var encodedHeaderPayload = $"{header}.{payload}"; var computedSignature = ComputeHmacSha256Signature(encodedHeaderPayload, secretKey); if (computedSignature != signature) return false; // 解码Payload并验证过期时间 var decodedPayload = Base64UrlDecode(payload); var serializer = new JavaScriptSerializer(); var payloadData = serializer.Deserialize<Dictionary<string, object>>(decodedPayload); if (payloadData.ContainsKey("exp")) { var expTime = UnixTimeStampToDateTime(Convert.ToDouble(payloadData["exp"])); if (expTime < DateTime.UtcNow) return false; } // 这里可以添加更多自定义验证逻辑,比如iss、aud等 return true; } private static string ComputeHmacSha256Signature(string input, string secretKey) { var encoding = new UTF8Encoding(); var secretBytes = encoding.GetBytes(secretKey); var inputBytes = encoding.GetBytes(input); using (var hmac = new HMACSHA256(secretBytes)) { var hashBytes = hmac.ComputeHash(inputBytes); return Base64UrlEncode(hashBytes); } } private static string Base64UrlEncode(byte[] input) { var base64 = Convert.ToBase64String(input); return base64.Replace('+', '-').Replace('/', '_').TrimEnd('='); } private static string Base64UrlDecode(string input) { input = input.Replace('-', '+').Replace('_', '/'); switch (input.Length % 4) { case 2: input += "=="; break; case 3: input += "="; break; } var decodedBytes = Convert.FromBase64String(input); return Encoding.UTF8.GetString(decodedBytes); } private static DateTime UnixTimeStampToDateTime(double unixTimeStamp) { var dtDateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc); dtDateTime = dtDateTime.AddSeconds(unixTimeStamp).ToLocalTime(); return dtDateTime; } } }
额外注意事项
- .NET Framework 3.5默认使用TLS 1.0,而现在大多数身份提供商要求TLS 1.2及以上。如果你的验证过程需要调用远程接口获取公钥(比如RS256签名的情况),需要在代码开头添加:
System.Net.ServicePointManager.SecurityProtocol = (System.Net.SecurityProtocolType)3072; // TLS 1.2 - 如果你用的是RS256等非对称签名算法,手动验证会更复杂,推荐优先用第三方库来处理。
内容的提问来源于stack exchange,提问作者Setu Kumar Basak
相关产品推荐
相关产品推荐

