简体   繁体   中英

ASP .NET Core cookie authentication

I have an ASP.NET Web API site that is using an authentication cookie generated from another ASP.NET Web Form site.
Since both the ASP.NET Web API site and the ASP.NET Web Form site have the same "machineKey" and same "form auth cookie name", it would allow a user to login to the "Web Form Site" and then pull data from the "Web API Site" without re-authentication since the "auth" cookie would pass between sites.
All this was done inside that web.config and did not require any special code to work.

Now we would like to create an ASP NET Core Web API site and have that same auth cookie work.

I can't seem to find any good articles on how do this in .NET Core.
There are plenty of articles on how to us ASP Identity which we don't have and plenty of articles on auth cookies but none explaining how to get it from another site...

Here is the web.config sections that I had in the Web API:

  <system.web>
    <authentication>
      <forms name=".TESTAUTH" cookieless="AutoDetect" requireSSL="true" domain=".test.com" slidingExpiration="true" protection="All" timeout="600"
             enableCrossAppRedirects="true" />
    </authentication>

    <!-- This is used to share the auth cookie between web sites -->
    <machineKey validationKey="SOMEKEY"
                decryptionKey="SOMEOTHERKEY" validation="SHA1" decryption="AES" compatibilityMode="Framework20SP2" />
  </system.web>

EDIT A
We are using "Framework20SP2" and that seems to complicate the issue.
Here is a link to some code that will decrypt the auth ticket based on "Framework20SP2"
https://github.com/dazinator/AspNetCore.LegacyAuthCookieCompat

If I use the NuGet above, it does decrypt the auth cookie in the .NET Core site but I can't seem to figure out how to get that to work in the .NET Core DataProtectionProvider.

The first thing you need to confirm is that the applications are hosted on same domain or subdomains of that domain. Otherwise consider using token/sso service like Identity Server 4/Azure AD to implement SSO.

ASP.NET 4.x apps that use Katana Cookie Authentication Middleware can be configured to generate authentication cookies that are compatible with the ASP.NET Core Cookie Authentication Middleware.Install the Microsoft.Owin.Security.Interop package into ASP.NET 4.x app to use DataProtectionProvider, which provides data protection services for the encryption and decryption of authentication cookie payload data.

You can now remove machineKey config, the Katana cookies middleware uses data protection, that doesn't rely on machine keys but on a key ring persisted,you should ensure that it uses a persisted key storage, and that key storage is accessible and used by each application.

See below article for more details and code sample:

https://docs.microsoft.com/en-us/aspnet/core/security/cookie-sharing?view=aspnetcore-3.0

While this works, I'm not 100% sure it is the best / proper way of doing this but
here is the main class I created.

public class FormsAuthCookieTicketFormat : ISecureDataFormat<AuthenticationTicket>
{

    private LegacyFormsAuthenticationTicketEncryptor _Encryptor;
    private Sha1HashProvider _HashProvider;

    public FormsAuthCookieTicketFormat(string decryptionKey, string validationKey)
    {
        byte[] decryptionKeyBytes = HexUtils.HexToBinary(decryptionKey);
        byte[] validationKeyBytes = HexUtils.HexToBinary(validationKey);

        _Encryptor = new LegacyFormsAuthenticationTicketEncryptor(decryptionKeyBytes, validationKeyBytes, ShaVersion.Sha1, CompatibilityMode.Framework20SP2);
        _HashProvider = new Sha1HashProvider(validationKeyBytes);
    }

    public string Protect(AuthenticationTicket data)
    {
        throw new NotImplementedException();
    }

    public string Protect(AuthenticationTicket data, string purpose)
    {
        throw new NotImplementedException();
    }

    public AuthenticationTicket Unprotect(string protectedText)
    {
        throw new NotImplementedException();
    }

    public AuthenticationTicket Unprotect(string protectedText, string purpose)
    {
        var ticket = _Encryptor.DecryptCookie(protectedText);


        var identity = new ClaimsIdentity("MyCookie");
        identity.AddClaim(new Claim(ClaimTypes.Name, ticket.Name));
        identity.AddClaim(new Claim(ClaimTypes.IsPersistent, ticket.IsPersistent.ToString()));
        identity.AddClaim(new Claim(ClaimTypes.Expired, ticket.Expired.ToString()));
        identity.AddClaim(new Claim(ClaimTypes.Expiration, ticket.Expiration.ToString()));
        identity.AddClaim(new Claim(ClaimTypes.CookiePath, ticket.CookiePath));
        identity.AddClaim(new Claim(ClaimTypes.Version, ticket.Version.ToString()));

        // Add some additional properties to the authentication ticket.
        var props = new AuthenticationProperties();
        props.ExpiresUtc = ticket.Expiration.ToUniversalTime();
        props.IsPersistent = ticket.IsPersistent;

        var principal = new ClaimsPrincipal(identity);


        var authTicket = new AuthenticationTicket(principal, props, CookieAuthenticationDefaults.AuthenticationScheme);
        return authTicket;
    }
}

Here is the Startup.cs file

var formsCookieFormat = new FormsAuthCookieTicketFormat(decryptionKey, validationKey);

services
    .AddAuthentication(options =>
    {
        options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    })
    .AddCookie(options =>
    {
        options.Cookie.Name = ".TESTCOOKIE";
        options.Cookie.Domain = ".TESTDOMAIN";
        options.Cookie.Path = "/";
        options.Cookie.HttpOnly = false;
        options.Cookie.SameSite = SameSiteMode.None;
        options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
        options.AccessDeniedPath = "/Login/";
        options.LoginPath = "/Login/";
        options.ReturnUrlParameter = "returnurl";
        options.ExpireTimeSpan = TimeSpan.FromMinutes(20);
        options.TicketDataFormat = formsCookieFormat;
        options.SlidingExpiration = true;
    });

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM