ASP.NET .Net 和 Core 上跨子域的身份 Cookie

ASP.NET Identity Cookie across subdomains on .Net and Core

我有很多应用程序托管在主域和子域上:

网站 A,ASP.NET (.Net Core 2.0) www.example.com

网站 B,ASP.NET MVC(4.7 .net Framework)位于 site.example.com

Website C, ASP.NET Identity (.Net Core 2.0) at account.example.com

网站 D,ASP.NET Webform (4.7 .net Framework) 在 file.example.com

我想在 account.example.com 上登录使用,验证后用户将被重定向到其他网站。他们将通过其他网站上的角色获得授权。

我正在尝试在这些网站之间共享 cookie,并且所有网站都托管在 Azure Web App

我正在使用 ASP.NET Identity (.Net Core 2.0)。我正在使用内置的 cookie 身份验证。

如何在所有应用程序中使用数据保护并在它们之间共享 cookie。

对于数据保护,我的代码是:

 services.AddDataProtection()
            .SetApplicationName("example")
            .PersistKeysToFileSystem(new DirectoryInfo(@"%HOME%\ASP.NET\DataProtection-Keys"))
            .SetDefaultKeyLifetime(TimeSpan.FromDays(14));

对于 Cookie 身份验证,我的代码是:

 app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
            LoginPath = new PathString("/Account/Login"),
            CookieDomain = ".example.com"
        });

关于.Net Core,如果你想在多个站点之间共享你的cookie,你可以尝试以下方式来初始化它而不是UseCookieAuthentication:

services.AddAuthentication();
services.ConfigureApplicationCookie(options =>
{
    // Cookie settings
    options.Cookie.SameSite = Microsoft.AspNetCore.Http.SameSiteMode.Lax;
    options.Cookie.Name = "CookieName";

    //options.Cookie.Domain = ".localhost";
    if (!CurrentEnvironment.IsDevelopment())
        options.Cookie.Domain = CommonConfig.CookieDomain; // ".mydomain.com"

    options.Cookie.HttpOnly = false;

    options.Cookie.Expiration = TimeSpan.FromDays(5 * 30);
    options.SlidingExpiration = true;
    options.Cookie.SecurePolicy = Microsoft.AspNetCore.Http.CookieSecurePolicy.Always;

    options.LoginPath = new PathString("/Account/Login"); 
    options.LogoutPath = new PathString("/Account/Logoff"); 
    options.AccessDeniedPath = new PathString("/Account/Login"); 


    var protectionProvider = DataProtectionProvider.Create(new DirectoryInfo(CommonConfig.PersistKeysStoreC));
    options.DataProtectionProvider = protectionProvider;

    // This adds claims data to the cookie...
    options.Events.OnSignedIn = async (context) =>
        {   
            System.Security.Claims.ClaimsIdentity identity = (System.Security.Claims.ClaimsIdentity)context.Principal.Identity;

            UserManager<AppUser> userManager = context.HttpContext.RequestServices.GetService<UserManager<AppUser>>();
            AppUser user = await userManager.GetUserAsync(context.Principal);
            identity.AddClaim(new System.Security.Claims.Claim(System.Security.Claims.ClaimTypes.NameIdentifier, user.Id.ToString()));
            //identity.AddClaim(new System.Security.Claims.Claim(System.Security.Claims.ClaimTypes.Email, user.Email.ToString()));
            //identity.AddClaim(new System.Security.Claims.Claim(System.Security.Claims.ClaimTypes.Name, user.LastName));
            //identity.AddClaim(new System.Security.Claims.Claim(System.Security.Claims.ClaimTypes.GivenName, user.FirstName));
        };
});

当然,您需要为所有站点提供相同的 ProtectionProvider 路径。

我从这个 Microsoft 文档中得到了解决方案

Share cookies among apps with ASP.NET and ASP.NET Core

以及此 sub-domain 身份验证系统的示例代码

Cookie Sharing Sample App - GitHub

The sample illustrates cookie sharing across three apps that use cookie authentication:

  • ASP.NET Core 2.0 Razor Pages 应用,不使用 ASP.NET Core Identity
  • ASP.NET 具有 ASP.NET Core Identity
  • 的 Core 2.0 MVC 应用程序
  • ASP.NET Framework 4.6.1 MVC 应用 ASP.NET Identity

Put this code in your ConfigureServices method in Startup.cs

services.AddDataProtection()
.PersistKeysToFileSystem(GetKeyRingDirInfo())
.SetApplicationName("example");

services.ConfigureApplicationCookie(options => 
{   
options.Cookie.Name = "example";
options.Cookie.Domain = ".example.com";
});

For KeyRing method

private DirectoryInfo GetKeyRingDirInfo()
    {
        var startupAssembly = System.Reflection.Assembly.GetExecutingAssembly();
        var applicationBasePath = System.AppContext.BaseDirectory;
        var directoryInfo = new DirectoryInfo(applicationBasePath);
        do
        {
            directoryInfo = directoryInfo.Parent;

            var keyRingDirectoryInfo = new DirectoryInfo(Path.Combine(directoryInfo.FullName, "KeyRing"));
            if (keyRingDirectoryInfo.Exists)
            {
                return keyRingDirectoryInfo;
            }
        }
        while (directoryInfo.Parent != null);

        throw new Exception($"KeyRing folder could not be located using the application root {applicationBasePath}.");
    }

Note : You have to copy KeyRing file which is automatically generated on Identity application hosting server and manually paste to other sub-domain and main domain hosting server of other website to share cookie for authentication.