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

如何在Owin Startup中传递值从OnRedirectToIdentityProvider到OnAuthenticationFailed

解决Owin OIDC中OnRedirectToIdentityProvider与OnAuthenticationFailed间传递数据的问题

核心原因说明

OnRedirectToIdentityProvider和OnAuthenticationFailed属于两次独立的请求上下文:重定向到身份提供商是一次请求,回调回来是全新的请求,所以直接通过Add.Environment或setParameter无法跨请求传递数据,需要用跨请求的存储或协议参数嵌入的方式实现。

可行解决方案

方案1:加密嵌入OIDC的State参数传递数据

OIDC的State参数本身用于CSRF防护,我们可以在其中附加加密后的自定义数据,回调时解析获取:

public void Configuration(IAppBuilder app)
{
    app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
    {
        // 其他基础配置...
        OnRedirectToIdentityProvider = context =>
        {
            // 定义要传递的自定义数据
            var customPayload = new 
            { 
                Env = Environment.GetEnvironmentVariable("APP_ENV"),
                TraceId = Guid.NewGuid().ToString()
            };
            var jsonPayload = JsonConvert.SerializeObject(customPayload);
            var encryptedPayload = ProtectData(jsonPayload); // 加密防止篡改

            // 把自定义数据附加到原有State后
            var originalState = context.ProtocolMessage.State;
            context.ProtocolMessage.State = $"{originalState}|{encryptedPayload}";

            return Task.CompletedTask;
        },
        OnAuthenticationFailed = context =>
        {
            // 拆分State并解析自定义数据
            var stateSegments = context.ProtocolMessage.State.Split('|');
            if (stateSegments.Length == 2)
            {
                var encryptedPayload = stateSegments[1];
                var jsonPayload = UnprotectData(encryptedPayload);
                var customPayload = JsonConvert.DeserializeObject<dynamic>(jsonPayload);
                
                // 访问自定义数据
                string env = customPayload.Env;
                string traceId = customPayload.TraceId;
            }

            // 错误处理逻辑
            context.HandleResponse();
            context.Response.Redirect("/Error?msg=" + Uri.EscapeDataString(context.Exception.Message));
            return Task.CompletedTask;
        }
    });
}

// 基于DataProtection的加密解密辅助方法
private string ProtectData(string rawData)
{
    var protector = new DpapiDataProtectionProvider("YourOidcAppName")
        .CreateProtector("OidcCustomData");
    return protector.Protect(rawData);
}

private string UnprotectData(string protectedData)
{
    var protector = new DpapiDataProtectionProvider("YourOidcAppName")
        .CreateProtector("OidcCustomData");
    return protector.Unprotect(protectedData);
}

方案2:使用会话/分布式缓存存储数据

如果应用已启用会话或有分布式缓存(如Redis),可以用唯一请求ID作为键存储数据,通过State传递ID来关联:

public void Configuration(IAppBuilder app)
{
    // 先启用会话(未启用时添加)
    app.UseSession();

    app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
    {
        // 其他基础配置...
        OnRedirectToIdentityProvider = context =>
        {
            var requestId = Guid.NewGuid().ToString();
            // 存储自定义数据到会话
            context.OwinContext.Session[$"OidcData_{requestId}"] = new 
            { 
                Env = Environment.GetEnvironmentVariable("APP_ENV"),
                Timestamp = DateTime.UtcNow
            };

            // 将requestId附加到State
            var originalState = context.ProtocolMessage.State;
            context.ProtocolMessage.State = $"{originalState}|{requestId}";

            return Task.CompletedTask;
        },
        OnAuthenticationFailed = context =>
        {
            var stateSegments = context.ProtocolMessage.State.Split('|');
            if (stateSegments.Length == 2)
            {
                var requestId = stateSegments[1];
                var customData = context.OwinContext.Session[$"OidcData_{requestId}"];
                
                // 访问数据后清理会话存储
                context.OwinContext.Session.Remove($"OidcData_{requestId}");
            }

            // 错误处理逻辑
            context.HandleResponse();
            context.Response.Redirect("/Error");
            return Task.CompletedTask;
        }
    });
}

原方法失效的原因

  • setParameter是给发送到身份提供商的协议消息添加参数,这些参数不会被身份提供商主动带回你的应用,因此回调时无法获取。
  • Add.Environment是给当前请求的Owin上下文添加数据,但重定向后原上下文已销毁,回调请求是全新的上下文,无法访问之前的数据。

内容的提问来源于stack exchange,提问作者user464291

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 09:07:17