.Net MVC中ADFS认证后重定向导致TempData数据丢失求助
解决ADFS重定向后TempData["OptionsVm"]丢失的问题
我之前也碰到过类似的TempData在外部ADFS重定向后丢失的情况,这种时好时坏的问题确实让人挠头。结合TempData的工作机制和ADFS认证的流程特点,给你几个针对性的解决方案:
1. 先确认Session的配置是否适配ADFS重定向场景
TempData本质是依赖Session实现的,所以首先要排查Session的配置是否能应对跨域/外部重定向的情况:
- 检查Startup中Session的Cookie配置,因为ADFS重定向属于跨站点跳转,需要确保Session Cookie的
SameSite属性设置为SameSiteMode.None,同时开启Secure=true(前提是你的站点用HTTPS,这也是ADFS的常见要求):services.AddSession(options => { options.Cookie.SameSite = SameSiteMode.None; options.Cookie.SecurePolicy = CookieSecurePolicy.Always; options.IdleTimeout = TimeSpan.FromMinutes(30); // 延长超时,避免ADFS认证耗时过长导致Session过期 }); - 确保在
Configure方法中正确启用了Session中间件,并且放在MVC中间件之前:app.UseSession(); app.UseRouting(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllerRoute(...); });
2. 调整TempData的读取/保留逻辑
TempData.Keep()和Peek()的使用时机很关键,你可能需要调整在重定向后的Action中的读取方式:
- 在跳转到ADFS前:只需要正常设置TempData即可,不需要提前调用
Keep():TempData["OptionsVm"] = optionsVm; return Challenge(new AuthenticationProperties { RedirectUri = "/ExternalLoginCallback" }, "ADFS"); - 在重定向回调的Action中:优先使用
Peek()来获取值(它不会标记数据为删除),或者先获取再调用Keep():
注意:如果你的回调Action之前有其他中间件或过滤器读取了TempData,即使你没用到,也会触发标记删除,所以要确保回调Action是第一个访问TempData的地方。// 方式1:用Peek直接获取,不标记删除 var optionsVm = TempData.Peek("OptionsVm") as OptionsVm; // 方式2:先获取,再手动保留(如果后续还需要用到该数据) var optionsVm = TempData["OptionsVm"] as OptionsVm; if (optionsVm != null) { TempData.Keep("OptionsVm"); }
3. 替换TempData:用加密Cookie持久化数据
由于ADFS重定向是跨外部站点的跳转,TempData(依赖Session)的稳定性可能受限于Session的生命周期和Cookie策略。更可靠的方式是把OptionsVm序列化后加密存到Cookie中:
- 先创建一个扩展方法来处理序列化、加密和解密:
public static class CookieExtensions { public static void SetEncryptedCookie(this HttpResponse response, string key, object value, IDataProtector protector) { var json = JsonSerializer.Serialize(value); var encryptedJson = protector.Protect(json); response.Cookies.Append(key, encryptedJson, new CookieOptions { SameSite = SameSiteMode.None, Secure = true, HttpOnly = true, Expires = DateTimeOffset.UtcNow.AddMinutes(30) }); } public static T GetEncryptedCookie<T>(this HttpRequest request, string key, IDataProtector protector) { if (!request.Cookies.TryGetValue(key, out var encryptedJson)) return default; var json = protector.Unprotect(encryptedJson); return JsonSerializer.Deserialize<T>(json); } } - 在Startup中注册数据保护服务(默认已经注册,但可以指定应用名称确保一致性):
services.AddDataProtection().SetApplicationName("YourAppName"); - 在跳转到ADFS前存Cookie:
var protector = HttpContext.RequestServices.GetRequiredService<IDataProtectionProvider>().CreateProtector("OptionsVmCookie"); Response.SetEncryptedCookie("OptionsVm", optionsVm, protector); return Challenge(new AuthenticationProperties { RedirectUri = "/ExternalLoginCallback" }, "ADFS"); - 在回调Action中读取Cookie:
var protector = HttpContext.RequestServices.GetRequiredService<IDataProtectionProvider>().CreateProtector("OptionsVmCookie"); var optionsVm = Request.GetEncryptedCookie<OptionsVm>("OptionsVm", protector); // 读取后可以删除Cookie Response.Cookies.Delete("OptionsVm");
4. 排查Session超时问题
ADFS认证流程可能需要用户输入凭证、跳转等操作,耗时如果超过了Session的IdleTimeout,就会导致Session过期,TempData自然丢失。可以适当延长Session的超时时间(比如设置为30分钟甚至更长),同时确保站点的应用池回收时间不会覆盖Session的超时设置。
内容的提问来源于stack exchange,提问作者bjp1125
相关产品推荐
相关产品推荐

