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

如何实现Asp.Net与Asp.Net Core应用基于Identity Server4共享access_token?

解决ASP.NET Core与经典ASP.NET(WebForms/MVC)间的Access Token共享问题

这个场景在混合新旧技术栈的项目里太常见了——虽然Data Protection帮我们搞定了跨应用的Cookie身份共享,但Access Token的存储和获取逻辑在两类框架里差异不小,导致Core登录后WebForms拿不到Token。下面给你几个实用的解决方案,按推荐程度排序:

方案1:让经典ASP.NET直接集成OpenID Connect(最标准的做法)

如果你的经典ASP.NET项目可以引入Owin中间件(大部分MVC/WebForms项目都支持),这是最靠谱的方案:让WebForms应用自己和Identity Server 4对接,走完整的OAuth2授权流程,这样它会自己获取并存储Access Token,同时因为共享了Cookie,用户在Core应用登录后访问WebForms会自动完成单点登录(SSO)。

经典ASP.NET(Owin)配置示例:

在项目的Startup.cs里添加如下配置:

public void Configuration(IAppBuilder app)
{
    // 配置共享身份Cookie(和Core用同一个名称、域名)
    app.UseCookieAuthentication(new CookieAuthenticationOptions
    {
        AuthenticationType = "Cookies",
        CookieName = ".SharedAuthCookie",
        CookieHttpOnly = true,
        CookieSecure = CookieSecureOption.Always, // 生产环境必须开启HTTPS
        CookieSameSite = SameSiteMode.Lax,
        CookieDomain = ".your-domain.com" // 统一主域名实现跨子域共享
    });

    // 对接Identity Server的OpenID Connect
    app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
    {
        Authority = "https://your-identity-server-url",
        ClientId = "webforms-app-client-id",
        ClientSecret = "webforms-app-client-secret",
        ResponseType = "code",
        Scope = "openid profile your-api-scope",
        RedirectUri = "https://your-webforms-app/signin-oidc",
        PostLogoutRedirectUri = "https://your-webforms-app/signout-callback-oidc",
        SaveTokens = true, // 自动将Token存入共享Cookie
        UseTokenLifetime = false
    });
}

之后在WebForms页面或MVC控制器里,就能直接从身份上下文获取Token:

// WebForms页面
protected void Page_Load(object sender, EventArgs e)
{
    var accessToken = Context.GetOwinContext().Authentication.User.FindFirst("access_token")?.Value;
    if (!string.IsNullOrEmpty(accessToken))
    {
        // 用Token调用内嵌API
        using (var client = new HttpClient())
        {
            client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
            var response = client.GetAsync("https://your-webforms-app/api/protected-endpoint").Result;
            // 处理响应逻辑
        }
    }
}

方案2:将Access Token写入共享加密Cookie(兼容老项目)

如果WebForms项目无法集成Owin,那可以利用已有的Data Protection共享机制,在ASP.NET Core登录成功后,把Access Token加密后写入共享Cookie,让WebForms读取并解密使用。

ASP.NET Core端:登录后写入Token到共享Cookie

在Core项目的OpenID Connect事件中,拿到Token后加密写入Cookie:

builder.Services.AddAuthentication(options =>
{
    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie(options =>
{
    options.Cookie.Name = ".SharedAuthCookie";
    options.Cookie.HttpOnly = true;
    options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
    options.Cookie.SameSite = SameSiteMode.Lax;
    options.Cookie.Domain = ".your-domain.com";
})
.AddOpenIdConnect(options =>
{
    options.Authority = "https://your-identity-server-url";
    options.ClientId = "core-app-client-id";
    options.ClientSecret = "core-app-client-secret";
    options.ResponseType = "code";
    options.SaveTokens = true;

    options.Events = new OpenIdConnectEvents
    {
        OnTokenValidated = async context =>
        {
            var accessToken = context.SecurityToken as JwtSecurityToken;
            if (accessToken != null)
            {
                var refreshToken = context.Properties.GetTokenValue("refresh_token");
                // 用Data Protection加密Token
                var dataProtector = context.HttpContext.RequestServices
                    .GetRequiredService<IDataProtectionProvider>()
                    .CreateProtector("SharedTokenProtectionKey");

                var encryptedAccessToken = dataProtector.Protect(accessToken.RawData);
                var encryptedRefreshToken = dataProtector.Protect(refreshToken);

                // 写入共享Cookie
                context.Response.Cookies.Append("SharedAccessToken", encryptedAccessToken, new CookieOptions
                {
                    HttpOnly = true,
                    Secure = true,
                    SameSite = SameSiteMode.Lax,
                    Expires = accessToken.ValidTo,
                    Path = "/",
                    Domain = ".your-domain.com"
                });
            }
            await Task.CompletedTask;
        }
    };
});

经典ASP.NET端:读取并解密Token

先在Global.asax中配置Data Protection(和Core共享密钥存储):

protected void Application_Start()
{
    // 共享Core的Data Protection密钥
    var dataProtectionProvider = DataProtectionProvider.Create(
        new DirectoryInfo(@"\\shared-server\dataprotection-keys"), // 和Core用同一个密钥目录
        config => config.SetApplicationName("YourSharedAppName"));
    
    Application["DataProtectionProvider"] = dataProtectionProvider;
}

然后在WebForms页面中读取解密:

protected void Page_Load(object sender, EventArgs e)
{
    var dataProtectionProvider = (IDataProtectionProvider)Application["DataProtectionProvider"];
    var dataProtector = dataProtectionProvider.CreateProtector("SharedTokenProtectionKey");

    var tokenCookie = Request.Cookies["SharedAccessToken"];
    if (tokenCookie != null)
    {
        try
        {
            var accessToken = dataProtector.Unprotect(tokenCookie.Value);
            // 用Token调用API逻辑
        }
        catch (CryptographicException)
        {
            // 解密失败(密钥不匹配/Token过期),跳转登录页
            Response.Redirect("https://your-identity-server-url/account/login?returnUrl=" + Request.Url);
        }
    }
    else
    {
        // 无Token,跳转登录
        Response.Redirect("https://your-identity-server-url/account/login?returnUrl=" + Request.Url);
    }
}

关键安全注意事项

  • 必须用HTTPS:所有Cookie都要开启Secure属性,防止Token被明文传输。
  • HttpOnly Cookie:Token相关Cookie必须设置HttpOnly,避免XSS攻击窃取。
  • Token过期同步:Cookie的过期时间要和Access Token的有效期保持一致,避免无效Token残留。
  • 密钥管理:Data Protection的密钥要存储在共享安全位置(如文件服务器、Azure Key Vault),不要硬编码在项目中。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 07:11:21