与 .NET Core 应用程序共享 ASP.NET Owin Cookie,同时将密钥保留到 Azure 存储

mar*_*ght 6 c# asp.net cookies azure-blob-storage asp.net-core

我们有一个针对 ASP.Net Framework (4.7.2) 构建的 WebForms 应用程序,该应用程序使用 OWIN cookie 身份验证。作为向 .Net Core 迁移的一部分,我们希望在 .Net Core (2.1) API 应用程序中使用 cookie。

WebForms 应用程序在 Azure 中运行,并利用DataProtectionStartup挂钩到IServiceCollection 机器密钥文件来使用 Microsoft 文档中的PersistKeysToAzureBlobStorage方法。Microsoft.AspNetCore.DataProtection

网页表格DataProtectionStartup

    services.AddDataProtection()
        .PersistKeysToAzureBlobStorage(blockblob)
        .SetApplicationName("OurAppName");
Run Code Online (Sandbox Code Playgroud)

.Net核心APIStartup

    services.AddDataProtection()
        .PersistKeysToAzureBlobStorage(blockblob)
        .SetApplicationName("OurAppName");
Run Code Online (Sandbox Code Playgroud)

两个应用程序都可以愉快地运行,生成机器密钥并将其存储在 blob 存储中。

Microsoft 有 文档 详细介绍了如何使用 DataProtectorShimfrom Microsoft.Owin.Security.Interop. 需要从共享计算机密钥DataProtectionShim生成DataProtectionProvider ,在文档中,两个应用程序都引用了该密钥来创建 cookie,并使用DataProtectionProvider.Create()将文件位置作为参数的方法。

当我们使用DataProtectionblob 存储时,我们没有这个位置。我们尝试 DataProtectionProvider.Create() 在两个应用程序上仅使用应用程序名称,因为它将使用 blob 存储密钥文件。不幸的是,这不会创建跨两个应用程序都有效的 cookie。

OWIN cookie 身份验证设置OwinStartup

    app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationType = 'Identity.Application',
            AuthenticationMode = Microsoft.Owin.Security.AuthenticationMode.Active,
            LoginPath = new PathString("/login.aspx"),
            CookieName = "AppCookieName",
            ExpireTimeSpan = 300,
            SlidingExpiration = true,

            Provider = new CookieAuthenticationProvider
            {
                OnValidateIdentity =
                    SecurityStampValidator
                        .OnValidateIdentity<UserManager, User, int>(
                            validateInterval: TimeSpan.FromMinutes(30),
                            regenerateIdentityCallback: (manager, user) =>
                                manager.CreateIdentityAsync(user, 'Identity.Application'),
                            getUserIdCallback: (user) => user.GetUserId<int>())
            },
            TicketDataFormat = new AspNetTicketDataFormat(
                new DataProtectorShim(
                    DataProtectionProvider.Create("OurAppName")
                        .CreateProtector(
                            "Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationMiddleware",
                            'Identity.Application',
                            "v2")
                        )),

            CookieManager = new ChunkingCookieManager()
        });
Run Code Online (Sandbox Code Playgroud)

我们的 .Net Core Startupcookie 设置:

    services.AddAuthentication("Identity.Application")
        .AddCookie("Identity.Application", options =>
        {
            options.Cookie.Name = "AppCookieName";
        });
Run Code Online (Sandbox Code Playgroud)

以前有人遇到过这种情况吗?我们发现的所有示例都只是 DataProtectionProvider.Create() 与计算机密钥文件位置一起使用的示例,并且没有找到有关如何使用该方法完成此PersistKeysToAzureBlobStorage操作的指导。

Mah*_*kar 5

我试图做同样的事情,想要在新的 Asp.Net Core Web 应用程序和具有 Asp.Net 身份验证的旧版 WebForms 项目之间共享 cookie。

我希望这个答案可以帮助那些尝试在 Asp.Net WebForms 中设置 cookie 身份验证的人,并且能够将保护密钥存储在共享目录路径之外的其他位置。

"DataProtectionProvider.Create" provides an action with IDataProtectionBuilder which can be used to overwrite key directory and store key in cloud (azure blob storage)
Run Code Online (Sandbox Code Playgroud)

如果 webforms 项目具有 Azure.Extensions.AspNetCore.DataProtection.Blobs nuget 包安装密钥可以存储在 azure blob 存储中

例如

WebForms project identity cookie authentication setup.

app.UseCookieAuthentication(new CookieAuthenticationOptions
            {
                CookieName = $"SharedCookieName",
                CookieDomain = "SharedDomain",
                CookieSameSite = SameSiteMode.Lax,
                CookiePath = "/",
                CookieHttpOnly = true,
                ExpireTimeSpan = TimeSpan.FromMinutes(30),
                AuthenticationType = "Identity.Application",
                LoginPath = new PathString("/Account/Login"),
                Provider = new CookieAuthenticationProvider
                {
                    OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser, int>(
                        validateInterval: TimeSpan.FromMinutes(30),
                        regenerateIdentityCallback: (manager, user) => user.GenerateUserIdentityAsync(manager),
                        getUserIdCallback: (id) => (id.GetUserId<int>()))
                },

                // Note: (new DirectoryInfo(@"\")  dummy directory to satisfy DataProtectionProvider.Create and than overwrite key storage with PersistKeysToAzureBlobStorage
                TicketDataFormat = new AspNetTicketDataFormat(new DataProtectorShim(DataProtectionProvider.Create(new DirectoryInfo(@"\"),
                                                        (builder) =>
                                                        {
                                                            builder.SetApplicationName("ShareApplicationName")
                                                            .PersistKeysToAzureBlobStorage("AzureBlobConnectionString","ContainerName", "key.xml");
                                                        })
                                                        .CreateProtector(
                                                           $"SomeSharedPurposeName",
                                                           "Identity.Application",
                                                           "v2"))),

                CookieManager = new Microsoft.Owin.Security.Interop.ChunkingCookieManager()
            });
Run Code Online (Sandbox Code Playgroud)
IDataProtectionBuilder has multiple extension methods to use blob storage differently. 

public static IDataProtectionBuilder PersistKeysToAzureBlobStorage(this IDataProtectionBuilder builder, Uri blobSasUri)

public static IDataProtectionBuilder PersistKeysToAzureBlobStorage(this IDataProtectionBuilder builder, Uri blobUri, TokenCredential tokenCredential)

public static IDataProtectionBuilder PersistKeysToAzureBlobStorage(this IDataProtectionBuilder builder, Uri blobUri, StorageSharedKeyCredential sharedKeyCredential)

public static IDataProtectionBuilder PersistKeysToAzureBlobStorage(this IDataProtectionBuilder builder, BlobClient blobClient)
Run Code Online (Sandbox Code Playgroud)

在设置应用程序 cookie 时,可以对 Asp.Net Core 使用相同的方法。

services.ConfigureApplicationCookie(options => { });
Run Code Online (Sandbox Code Playgroud)


Ran*_*agy 2

我最终做的是(ab)使用 DI 系统(使用 NuGet Microsoft.Extensions.DependencyInjection)来获得我想要的行为:

private static IDataProtector ConfigureDataProtection()
{
    // TODO this has to be wrong
    ServiceCollection services = new ServiceCollection();
    ConfigurationOptions configurationOptions = ConfigurationOptions.Parse("REDIS_CONNECTION_STRING_HERE");
    ConnectionMultiplexer rmp = ConnectionMultiplexer.Connect(configurationOptions);
    services.AddDataProtection()
        .SetApplicationName("APPNAME")
        .PersistKeysToStackExchangeRedis(rmp, "REDIS_DATA_PROTECTION_LIST_KEY");
    ServiceProvider provider = services.BuildServiceProvider();

    IDataProtectionProvider dataProtectionProvider = provider.GetRequiredService<IDataProtectionProvider>();
    return dataProtectionProvider.CreateProtector("Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationMiddleware", "Cookies" /* <- Auth Type to match the ASP.NET Core side, the rest is CRUCIAL and has to be the same purpose strings as internally used by ASP.NET Core */, "v2");
}
Run Code Online (Sandbox Code Playgroud)

虽然我的示例使用 Redis,但我想这同样适用于其他实现。