Microsoft.AspNetCore.Session.SessionMiddleware Error unprotecting the session cookie.
Microsoft.AspNetCore.Session.SessionMiddleware Error unprotecting the session cookie.
Microsoft.AspNetCore.Session.SessionMiddleware[7]
Error unprotecting the session cookie.
System.Security.Cryptography.CryptographicException: The key {4996c409-26ef-4716-a7c0-dede81a611a0} was not found in the key ring. For more information go to http://aka.ms/dataprotectionwarning
at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.UnprotectCore(Byte[] protectedData, Boolean allowOperationsOnRevokedKeys, UnprotectStatus& status)
at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.Unprotect(Byte[] protectedData)
at Microsoft.AspNetCore.Session.CookieProtection.Unprotect(IDataProtector protector, String protectedText, ILogger logger)
Error unprotecting the session cookie.The payload was invalid
Startup的ConfigureServices方法:
services.AddSession(options =>
{
// Set a short timeout for easy testing.
options.IdleTimeout = TimeSpan.FromMinutes(60);
// You might want to only set the application cookies over a secure connection:
options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
options.Cookie.SameSite = SameSiteMode.Strict;
options.Cookie.HttpOnly = true;
// Make the session cookie essential
options.Cookie.IsEssential = true;
});
这次日志明确了错误根源:客户端 Cookie 是用密钥 {4996c409-26ef-4716-a7c0-dede81a611a0} 加密的,但当前应用的密钥环(key ring)中找不到该密钥,本质是“旧密钥丢失”导致无法解密旧 Cookie。以下是针对性解决方案:
1. 核心原因:旧密钥未被“保留”或“加载”
错误从之前的“payload 无效”变为“密钥找不到”,说明数据保护配置已部分生效(应用开始从持久化位置加载密钥),但:
- 加密旧 Cookie 的密钥({4996c409...})未被存储到持久化位置(如之前未配置持久化,密钥只在内存中,重启后丢失);
- 或持久化位置的密钥文件中,没有包含该旧密钥(仅存在新生成的密钥)。
此时客户端仍携带旧 Cookie 发起请求,应用用当前密钥环中的密钥解密,自然找不到匹配的密钥,导致失败。
2. 解决方案:分“临时缓解”和“彻底解决”两步
第一步:临时缓解——清除旧 Cookie,让客户端生成新 Cookie
这是最快消除警告的方式,适合需要立即恢复 Session 功能的场景:
- 方式1:服务端强制重置 Session Cookie
在Program.cs中修改 Session Cookie 的名称或路径,客户端会自动丢弃旧 Cookie,生成新的(用当前密钥加密的)Cookie:builder.Services.AddSession(options => { // 1. 修改 Cookie 名称(从默认的 .AspNetCore.Session 改为新名称) options.Cookie.Name = ".TodoApp.NewSession"; // 2. 可选:设置 Cookie 过期时间,加速旧 Cookie 失效 options.IdleTimeout = TimeSpan.FromMinutes(30); // 3. 可选:限制 Cookie 仅在 HTTPS 下传输(增强安全性) options.Cookie.SecurePolicy = CookieSecurePolicy.Always; }); - 方式2:客户端手动清除
指导用户在浏览器中清除当前应用域名的 Cookie(以 Chrome 为例):
浏览器设置 → 隐私和安全 → 网站设置 → Cookie 和站点数据 → 搜索应用域名(如localhost:5000)→ 删除所有相关 Cookie。
配置后重启应用,新请求会生成新 Cookie,警告会立即消失。
第二步:彻底解决——确保密钥“持久化+可复用”
临时缓解后,需确保后续密钥不会丢失,避免再次出现类似问题:
确认持久化配置正确且生效
再次检查AddDataProtection的配置,确保满足以下条件:- 配置在
AddSession之前(关键!); - 持久化目录是稳定的、非临时的(如宿主机目录、云存储挂载目录,非容器内部临时目录);
- 应用有权限读写该目录(可手动在目录中创建一个测试文件,确认应用能读取)。 正确配置示例:
// 步骤1:先配置数据保护,指定持久化目录和应用名 builder.Services.AddDataProtection() .PersistKeysToFileSystem(new DirectoryInfo(@"C:\TodoApp\DataProtectionKeys")) // 本地目录 // 或用 Redis 存储(分布式部署推荐) // .PersistKeysToStackExchangeRedis(ConnectionMultiplexer.Connect("127.0.0.1:6379"), "TodoApp:Keys") .SetApplicationName("TodoReminderApp") // 应用名唯一,避免与其他应用密钥混用 .ProtectKeysWithDpapi() // 可选:在 Windows 上用 DPAPI 加密密钥文件,增强安全性 .SetDefaultKeyLifetime(TimeSpan.FromDays(90)); // 设置密钥有效期(默认90天,到期自动轮换); // 步骤2:再配置 Session builder.Services.AddSession();- 配置在
验证密钥持久化效果
应用启动后,查看持久化目录(如C:\TodoApp\DataProtectionKeys):- 目录中会生成
key-xxxxxx.xml格式的密钥文件(每个文件对应一个密钥); - 重启应用后,不会重新生成大量新密钥文件(仅在旧密钥过期或被吊销时生成新的);
- 多实例部署时,所有实例指向同一个持久化目录(或 Redis),加载的密钥文件完全一致。
- 目录中会生成
3. 验证效果
配置完成后,通过以下步骤确认问题已彻底解决:
- 重启应用,观察日志是否还有“密钥找不到”的警告;
- 客户端发起请求,检查浏览器中是否生成了新的 Session Cookie(名称与配置的
options.Cookie.Name一致); - 再次重启应用,用同一客户端发起请求,确认 Session 状态能正常保持(如登录后刷新页面,无需重新登录);
- 查看持久化目录,确认密钥文件未被删除或篡改。
当前问题的核心是“旧密钥丢失+新密钥未匹配”,先通过修改 Cookie 名称快速消除警告,再通过正确的持久化配置确保后续密钥稳定,即可彻底解决。