You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.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():
    // 方式1:用Peek直接获取,不标记删除
    var optionsVm = TempData.Peek("OptionsVm") as OptionsVm;
    
    // 方式2:先获取,再手动保留(如果后续还需要用到该数据)
    var optionsVm = TempData["OptionsVm"] as OptionsVm;
    if (optionsVm != null)
    {
        TempData.Keep("OptionsVm");
    }
    
    注意:如果你的回调Action之前有其他中间件或过滤器读取了TempData,即使你没用到,也会触发标记删除,所以要确保回调Action是第一个访问TempData的地方。

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 06:55:39