ECDsa实例二次导入私钥触发ObjectDisposedException问题求助
解决ECDsa实例Dispose后重新导入同一私钥抛出ObjectDisposedException的问题
问题分析
你的代码核心问题在于JwtSigningKeyProvider中复用了同一个ECDsa实例,并在每次调用Get()时重复导入私钥;同时ECDsaSecurityKey会持有该ECDsa实例的强引用,结合JsonWebTokenHandler的内部处理逻辑,当第一个实例被Dispose后,第二次创建的新实例可能被底层残留的已释放引用干扰,导致抛出异常。
可行解决方案
以下两种方案均可解决该问题:
方案1:构造时一次性导入私钥,避免重复导入
修改JwtSigningKeyProvider,在构造函数中完成私钥导入,后续Get()直接返回已初始化的密钥:
using Microsoft.IdentityModel.JsonWebTokens; using Microsoft.IdentityModel.Tokens; using System.Security.Cryptography; namespace ECDsaDisposeBug; public class JwtSigningKeyProvider : IDisposable { const string privateKeyBase64 = "MIHcAgEBBEIAsukFBinjgL9KONxPRvunQGdaTEhIL9JpwlgW0NN0XzlmbENucgw4XTczjyjlF9AnJnJHg8vXoM2bH5MJy+42OeegBwYFK4EEACOhgYkDgYYABAF8Nt5oxNZ9VwQzjPCWai7/p8hI6sbCAQI8wDcWfQ2Cddrw4G7v5wu6+z26hGJSJY66wKl0ar4fN+JrbCMIYS9UugHAs3W75a/KtiNfVJ9tYwFM0CYWP2kAKg7Kbk3SXkXMW4Gdb4XeoDO+TQVTRfWoBYXXx1iVu0dOXv5NkGZFIkKAHg=="; readonly ECDsa _algorithm; readonly ECDsaSecurityKey _securityKey; public JwtSigningKeyProvider() { _algorithm = ECDsa.Create(); var privateKey = Convert.FromBase64String(privateKeyBase64); _algorithm.ImportECPrivateKey(new ReadOnlySpan<byte>(privateKey), out _); _securityKey = new ECDsaSecurityKey(_algorithm); } public AsymmetricSecurityKey Get() { return _securityKey; } public void Dispose() { _algorithm.Dispose(); GC.SuppressFinalize(this); } }
方案2:每次调用Get()时创建新的ECDsa实例
如果需要动态切换密钥,可以每次创建独立的ECDsa实例,避免实例间的干扰:
using Microsoft.IdentityModel.JsonWebTokens; using Microsoft.IdentityModel.Tokens; using System.Collections.Generic; using System.Security.Cryptography; namespace ECDsaDisposeBug; public class JwtSigningKeyProvider : IDisposable { const string privateKeyBase64 = "MIHcAgEBBEIAsukFBinjgL9KONxPRvunQGdaTEhIL9JpwlgW0NN0XzlmbENucgw4XTczjyjlF9AnJnJHg8vXoM2bH5MJy+42OeegBwYFK4EEACOhgYkDgYYABAF8Nt5oxNZ9VwQzjPCWai7/p8hI6sbCAQI8wDcWfQ2Cddrw4G7v5wu6+z26hGJSJY66wKl0ar4fN+JrbCMIYS9UugHAs3W75a/KtiNfVJ9tYwFM0CYWP2kAKg7Kbk3SXkXMW4Gdb4XeoDO+TQVTRfWoBYXXx1iVu0dOXv5NkGZFIkKAHg=="; readonly List<ECDsa> _algorithms = new List<ECDsa>(); public AsymmetricSecurityKey Get() { var algorithm = ECDsa.Create(); _algorithms.Add(algorithm); var privateKey = Convert.FromBase64String(privateKeyBase64); algorithm.ImportECPrivateKey(new ReadOnlySpan<byte>(privateKey), out _); return new ECDsaSecurityKey(algorithm); } public void Dispose() { foreach (var alg in _algorithms) { alg.Dispose(); } _algorithms.Clear(); GC.SuppressFinalize(this); } }
说明
两种方案均通过避免重复复用已释放实例的引用,消除了ObjectDisposedException的触发条件。方案1更适合固定密钥的场景,性能更优;方案2则适用于需要动态生成密钥的场景。
内容的提问来源于stack exchange,提问作者Doug Clutter
相关产品推荐
相关产品推荐

