ASP.NET Identity Cookie across subdomains on .Net and Core
Asked Answered
C

2

6

I have many application which is hosted on main domain and sub domains:

Website A, ASP.NET (.Net Core 2.0) at www.example.com

Website B, ASP.NET MVC (4.7 .net Framework) at site.example.com

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

Website D, ASP.NET Webform (4.7 .net Framework) at file.example.com

I would like to login uses on account.example.com, after authenticate users will redirected to other websites. They will be authorize by there roles on other websites.

I'm trying to share a cookie between these websites and all of the website are hosted on Azure Web App.

I am using ASP.NET Identity (.Net Core 2.0). I'm using the built-in cookie authentication.

How can I use Data Protection in all application and share cookie among them.

For Data Protection my code is:

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

For Cookie Authentication my code is:

 app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
            LoginPath = new PathString("/Account/Login"),
            CookieDomain = ".example.com"
        });
Chitarrone answered 3/3, 2018 at 11:47 Comment(0)
C
8

I got solution from this Microsoft documentation

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

And Sample code for this sub-domain authentication system

Cookie Sharing Sample App - GitHub

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

  • ASP.NET Core 2.0 Razor Pages app without using ASP.NET Core Identity
  • ASP.NET Core 2.0 MVC app with ASP.NET Core Identity
  • ASP.NET Framework 4.6.1 MVC app with 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.

Chitarrone answered 15/6, 2019 at 14:27 Comment(4)
Where can I find this KeyRing file on auzre app?Pigweed
You have to manually create KeyRing folder in azure app. Then Identity application will automatically automatically generate Data Protection file. Then fallow the above note further instructions for sub-domain and main domain authentication. To create KeyRIng folder open Azure Web App --> Go to Advanced Tools then GO. It will redirect to another portal Kudu Service a file explorer of your web app. In menu Debug Console --> open CMD --> navigate to Site option in file explore and crate the KeyRing folder.Chitarrone
HI I have two asp.net core 6 websites on the same server One is on identity.example.fr, the other one is on test.example.fr on the 2 websites I put this : builder.Services.AddDataProtection() .PersistKeysToFileSystem(new DirectoryInfo(@"C:\DATA")) .SetApplicationName("AAA"); builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) .AddCookie(options => { options.LoginPath = "/login"; options.Cookie.Domain = ".example.fr"; }); But if I am logged on identity.example.fr, I am not loged on the other one What's wrong ?Pat
The above code is for Live Server Demo, not for localhost. If you would like to test on local server then you have to comment the domain "options.Cookie.Domain = ".example.com";"Chitarrone
P
2

Regarding .Net Core, if you want to share your cookie among several sites, you may try the following to initialize it instead of 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));
        };
});

Of course you will need to give the same ProtectionProvider path for all sites.

Polysyllable answered 24/4, 2018 at 17:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.