将共享身份验证添加到经典 ASP.NET Web 窗体应用程序和 Web API 应用程序

Add shared authentication to a Classic ASP.NET Web Forms app and a Web API app

我正在用 Open Id Connect 替换共享 cookie 身份验证设计。

上下文:这两个网络应用目前使用 FormsAuthentication 共享 AuthCookie cookie 和 machineKeys.

系统:

问题 1:Microsoft 的 Open Id Connect 库需要 OWIN。我无法将经典 Web 窗体应用程序转换为 OWIN 应用程序,因为 OWIN 需要集成管道,这会破坏依赖于经典管道的 Spring.NET 库。

操作 1A:将 Web API 转换为 OWIN 并添加对 Open Id Connect 的支持。

操作 1B:将身份验证从经典站点移至 Web API。

问题 2:认证后我必须能够使用两个系统。

操作 2:在 Open Id Connect 重定向时,Web API 将使用存储在 Open Id Connect cookie 中的 JWT 不记名令牌。 Web API 将创建一个额外的 cookie (AuthCookie),经典应用程序将使用它。

问题 3:如何使这两个 cookie 保持同步?用户必须同时登录或注销两个系统。如果一个 cookie 被意外删除但另一个 cookie 没有被删除会怎样?

问题 4:Web API 未收到来自 Microsoft Open Id Connect 的 cookie,但对我的 Web API 的后续请求未收到 cookie,并且 HttpContext.Current.User 未收到正在设置。

经典 Web 表单代码:

<authentication mode="Forms">
        <forms loginUrl="webapi/login" name="LycheeAuthCookie" slidingExpiration="true" path="/" />
</authentication>

网页API代码:

Startup.cs:
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions { AuthenticationMode = AuthenticationMode.Passive }); //Web API should return 401 not redirect to /login. The SPA will handle that
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
                ClientId = Config.ApplicationId,
                Authority = authority,
                RedirectUri = $"webapi/openIdRedirect",
                PostLogoutRedirectUri = $"webapi/openIdLogout",
                ResponseType = OpenIdConnectResponseType.IdToken,
                Scope = OpenIdConnectScope.OpenIdProfile,
                AuthenticationMode = AuthenticationMode.Passive, //Web API should return 401 not redirect to /login. The SPA will handle that
});
...
private Task OnSecurityTokenValidated(SecurityTokenValidatedNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> context) //Called on Open Id Connect authentication success
        {
            var newTicket = new FormsAuthenticationTicket(1,
                userId,
                DateTime.Now.AddMinutes(int.Parse(claims.FindFirst("iat").Value)),
                false,
                DateTime.Now.AddMinutes(int.Parse(claims.FindFirst("exp").Value)),
                false,
                "roles and permissions",
                FormsAuthentication.FormsCookiePath);
            var cookie = new HttpCookie("AuthCookie");
            cookie.Value = FormsAuthentication.Encrypt(newTicket);
            cookie.Expires = newTicket.Expiration;
            HttpContext.Current.Response.Cookies.Add(cookie);
}
Redirect(redirectUrl);

如果您在同一个域(即“https://localhost”)上托管您的网站,并且共享同一个 .AspNet.Cookies,那么它就可以工作!

为这两个网站添加 OWIN 中间件,将您的项目设置为 IIS 集成管道模式,并添加以下 Startup.cs 文件:

位于“/”的网站 1 - 活动:

[assembly: OwinStartup(typeof(...MyStartup))]
namespace MyNamespace
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
            app.UseCookieAuthentication();
            app.UseOpenIdConnectAuthentication();
        }
    }
}

位于“/api”的网站 2 - 被动:

[assembly: OwinStartup(typeof(...MyStartup))]
namespace MyNamespace
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
            app.UseCookieAuthentication(new Microsoft.Owin.Security.Cookies.CookieAuthenticationOptions {
                AuthenticationType = CookieAuthenticationDefaults.AuthenticationType
            });
        }
    }
}