在 SSO 的旧 .Net Web Forms (aspx) 站点中使用 ASP.Net Core 2.2 Auth Cookie
Using ASP.Net Core 2.2 Auth Cookies in old .Net Web Forms (aspx) site for SSO
TLDR:如何获得旧版 Web 窗体应用程序理解的 Asp.Net Core 2.2 加密身份验证 cookie?
DR:
我发现自己处于这样一种情况,我试图让旧版 Web 表单 (aspx) 站点使用由新的闪亮的 .NET Core 2.2 MVC 站点在浏览器中设置的 auth cookie。有问题的 Web 窗体应用程序是用 Visual Basic 编写的,.Net Core 应用程序是用 C# 编写的。一切都由 IIS/IIS Express 托管(来自 Visual Studio)。
cookie 似乎设置得很好,为了让事情变得简单(目前),所有东西都托管在同一台机器上(我的 Windows 10 专业版 Dell XPS)。用于 cookie 加密的 encryption/machine 密钥位于磁盘上明确定义的位置。 .Net Core 应用程序(我们暂时称它为 "Auth Portal")基本上是 AWS Cognito 的前台。
在 Auth Portal 中,cookie 的配置方式如下 Startup.cs:
services.Configure<CookiePolicyOptions>(options =>
{
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
var keyDir = Configuration["AuthSettings:CookieEncryptionKeyDir"];
services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(keyDir))
.SetApplicationName(Configuration["ApplicationName"]);
services.AddCognitoIdentity();
services.AddSingleton(typeof(IAmazonCognitoIdentityProvider),
_ => new AmazonCognitoIdentityProviderClient(RegionEndpoint.APSoutheast2)); // Oh no you know I'm using Sydney!
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie();
services
.ConfigureApplicationCookie(options =>
{
var parseSucceeded = int.TryParse(Configuration["AuthSettings:CookieExpiryHours"],
out var cookieExpiry);
if (!parseSucceeded) _log.LogError("Failed to parse from configuration auth cookie expiry value");
parseSucceeded = bool.TryParse(Configuration["AuthSettings:SSLCookieOnly"], out var secureCookieOnly);
var securePolicy = secureCookieOnly ? CookieSecurePolicy.Always : CookieSecurePolicy.SameAsRequest;
if (!parseSucceeded) _log.LogError("Failed to parse from configuration cookie security policy");
options.Cookie.HttpOnly = true;
options.ExpireTimeSpan = TimeSpan.FromHours(cookieExpiry);
options.SlidingExpiration = true;
options.LoginPath = Configuration["AuthSettings:LoginUrl"];
options.LogoutPath = Configuration["AuthSettings:LogoutUrl"];
options.Cookie.Domain = Configuration["AuthSettings:TrustedDomains"];
options.Cookie.Name = Configuration["AuthSettings:CookieName"];
options.Cookie.SecurePolicy = securePolicy;
});
services
.Configure<SecurityStampValidatorOptions>(o =>
{
o.ValidationInterval = TimeSpan.FromHours(1);
});
services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardLimit = 2;
options.ForwardedForHeaderName = "X-Forwarded-For-Auth-Portal";
});
在 Web 窗体应用程序中,我正在替换现有的默认 sql 身份验证。这是在线资源似乎枯竭的地方。我可以制作一个自定义的会员提供者,我已经很容易做到了。但它不能(可以理解)开箱即用地理解现有的 cookie,即使我在表单身份验证设置中设置了 cookie 名称
<authentication mode="Forms">
<forms timeout="60" name="my.sso.cookie" requireSSL="false" path="/" />
</authentication>
<membership defaultProvider="CognitoMembershipProvider" userIsOnlineTimeWindow="60">
<providers>
<clear />
<add name="CognitoMembershipProvider" type="TheOldWebFormsApp.Authentication.CognitoMembershipProvider" applicationName="MyWebForms" enablePasswordRetrieval="true" enablePasswordReset="true" requiresQuestionAndAnswer="true" requiresUniqueEmail="false" passwordFormat="Clear" minRequiredNonalphanumericCharacters="0" minRequiredPasswordLength="3" maxInvalidPasswordAttempts="8" />
</providers>
</membership>
正如我所发现的那样,它只会覆盖现有的 cookie,我假设这是因为它将无法理解的 cookie 视为不存在的 cookie。
我想这是一个非常冗长的方式来询问我如何才能让这个旧的 Web 表单应用程序接受和解密 Auth Portal cookie?
干杯~!
不幸的是,这是不可能的。 ASP.NET Core 使用与 ASP.NET 完全不同的方法来加密 cookie。后者基于 "machine key",但 ASP.NET 核心使用数据保护提供程序和密钥环。两者从根本上是不兼容的,所以即使你可以 "share" cookie,这样每个人都能看到它,一个人将无法解密另一个人设置的 cookie。
可以与 ASP.NET MVC 5 成功共享 cookie,但那是因为它使用了 OWIN,并且数据保护内容与 OWIN 兼容。因此,尽管 MVC 5 本身也使用机器密钥,但可以改为使用数据保护,然后它可以与 ASP.NET 核心站点共享相同的数据保护密钥存储。但是,Web Forms 不支持 OWIN,因此无法在那里实现相同的目的。简而言之,这绝对不行。
另一种选择可能是依赖集中式身份提供者,例如 Identity Server、Auth0、Azure AD 等。有了这样的解决方案,就没有必要共享 cookie,因为每个站点都与提供者独立授权,但可以使用相同的用户帐户。实际登录发生在身份提供者处,然后由该身份提供者授权的每个站点都从身份提供者那里获得身份,然后可以设置自己的 cookie 或其他任何内容。
TLDR:如何获得旧版 Web 窗体应用程序理解的 Asp.Net Core 2.2 加密身份验证 cookie?
DR:
我发现自己处于这样一种情况,我试图让旧版 Web 表单 (aspx) 站点使用由新的闪亮的 .NET Core 2.2 MVC 站点在浏览器中设置的 auth cookie。有问题的 Web 窗体应用程序是用 Visual Basic 编写的,.Net Core 应用程序是用 C# 编写的。一切都由 IIS/IIS Express 托管(来自 Visual Studio)。
cookie 似乎设置得很好,为了让事情变得简单(目前),所有东西都托管在同一台机器上(我的 Windows 10 专业版 Dell XPS)。用于 cookie 加密的 encryption/machine 密钥位于磁盘上明确定义的位置。 .Net Core 应用程序(我们暂时称它为 "Auth Portal")基本上是 AWS Cognito 的前台。
在 Auth Portal 中,cookie 的配置方式如下 Startup.cs:
services.Configure<CookiePolicyOptions>(options =>
{
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
var keyDir = Configuration["AuthSettings:CookieEncryptionKeyDir"];
services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(keyDir))
.SetApplicationName(Configuration["ApplicationName"]);
services.AddCognitoIdentity();
services.AddSingleton(typeof(IAmazonCognitoIdentityProvider),
_ => new AmazonCognitoIdentityProviderClient(RegionEndpoint.APSoutheast2)); // Oh no you know I'm using Sydney!
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie();
services
.ConfigureApplicationCookie(options =>
{
var parseSucceeded = int.TryParse(Configuration["AuthSettings:CookieExpiryHours"],
out var cookieExpiry);
if (!parseSucceeded) _log.LogError("Failed to parse from configuration auth cookie expiry value");
parseSucceeded = bool.TryParse(Configuration["AuthSettings:SSLCookieOnly"], out var secureCookieOnly);
var securePolicy = secureCookieOnly ? CookieSecurePolicy.Always : CookieSecurePolicy.SameAsRequest;
if (!parseSucceeded) _log.LogError("Failed to parse from configuration cookie security policy");
options.Cookie.HttpOnly = true;
options.ExpireTimeSpan = TimeSpan.FromHours(cookieExpiry);
options.SlidingExpiration = true;
options.LoginPath = Configuration["AuthSettings:LoginUrl"];
options.LogoutPath = Configuration["AuthSettings:LogoutUrl"];
options.Cookie.Domain = Configuration["AuthSettings:TrustedDomains"];
options.Cookie.Name = Configuration["AuthSettings:CookieName"];
options.Cookie.SecurePolicy = securePolicy;
});
services
.Configure<SecurityStampValidatorOptions>(o =>
{
o.ValidationInterval = TimeSpan.FromHours(1);
});
services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardLimit = 2;
options.ForwardedForHeaderName = "X-Forwarded-For-Auth-Portal";
});
在 Web 窗体应用程序中,我正在替换现有的默认 sql 身份验证。这是在线资源似乎枯竭的地方。我可以制作一个自定义的会员提供者,我已经很容易做到了。但它不能(可以理解)开箱即用地理解现有的 cookie,即使我在表单身份验证设置中设置了 cookie 名称
<authentication mode="Forms">
<forms timeout="60" name="my.sso.cookie" requireSSL="false" path="/" />
</authentication>
<membership defaultProvider="CognitoMembershipProvider" userIsOnlineTimeWindow="60">
<providers>
<clear />
<add name="CognitoMembershipProvider" type="TheOldWebFormsApp.Authentication.CognitoMembershipProvider" applicationName="MyWebForms" enablePasswordRetrieval="true" enablePasswordReset="true" requiresQuestionAndAnswer="true" requiresUniqueEmail="false" passwordFormat="Clear" minRequiredNonalphanumericCharacters="0" minRequiredPasswordLength="3" maxInvalidPasswordAttempts="8" />
</providers>
</membership>
正如我所发现的那样,它只会覆盖现有的 cookie,我假设这是因为它将无法理解的 cookie 视为不存在的 cookie。
我想这是一个非常冗长的方式来询问我如何才能让这个旧的 Web 表单应用程序接受和解密 Auth Portal cookie?
干杯~!
不幸的是,这是不可能的。 ASP.NET Core 使用与 ASP.NET 完全不同的方法来加密 cookie。后者基于 "machine key",但 ASP.NET 核心使用数据保护提供程序和密钥环。两者从根本上是不兼容的,所以即使你可以 "share" cookie,这样每个人都能看到它,一个人将无法解密另一个人设置的 cookie。
可以与 ASP.NET MVC 5 成功共享 cookie,但那是因为它使用了 OWIN,并且数据保护内容与 OWIN 兼容。因此,尽管 MVC 5 本身也使用机器密钥,但可以改为使用数据保护,然后它可以与 ASP.NET 核心站点共享相同的数据保护密钥存储。但是,Web Forms 不支持 OWIN,因此无法在那里实现相同的目的。简而言之,这绝对不行。
另一种选择可能是依赖集中式身份提供者,例如 Identity Server、Auth0、Azure AD 等。有了这样的解决方案,就没有必要共享 cookie,因为每个站点都与提供者独立授权,但可以使用相同的用户帐户。实际登录发生在身份提供者处,然后由该身份提供者授权的每个站点都从身份提供者那里获得身份,然后可以设置自己的 cookie 或其他任何内容。