Cookie-based Forms Authentication Across MVC 5 and ASP.NET Core applications

10.5k views Asked by At

I have used forms authentication across different sites already, even between different versions of .NET, but now we're looking into starting a new project in ASP.NET 5 (MVC 6) ASP.NET Core and would like to use cookie-based forms authentication across both. The login is done in "old" MVC 5 application.

Is some cross-applications configuration for cookie-based forms authentication even possible or supported with current version of ASP.NET 5? Could this be implemented on MVC6 ASP.NET Core side using FormsAuthenticationModule or can it play along somehow with the new authentication middleware? Any other suggestions?

3

There are 3 answers

2
natemcmaster On

WebForms is not a part of ASP.NET 5. This is change #2 according to this blog post

Updated

The new lifecycle of ASP.NET MVC 6 uses a middleware to compose services. You can use Security package to authenticate, but the old "Forms" authentication is not supported anymore.

4
Kisbys On

I have been beating my head over this same problem for the last few days... but I have solved it... (it seems to be holding up)

This is for converting windows and later forms Authentication to forms Authentication for MVC5 and MVC6 so hopefully you can change enough code to make it work for you... I plan to change some parts when I re-write the login scripts. (and this is alpha so will be making some changes!)

I put the following code in our MVC5 Intranet Site to grab the Roles for windows Authentication

protected void Application_PostAuthenticateRequest(Object sender, EventArgs e)
    {
        // Get current windows Identity to get the roles out of it
        WindowsIdentity ident = WindowsIdentity.GetCurrent();

        string[] roles = new string[ident.Groups.Count];
        int i = 0;

        // get the groups from the current Identity
        foreach (var g in ident.Groups)
        {

            roles[i] = g.Translate(typeof(System.Security.Principal.NTAccount)).Value.ToString();
            i++;
        }

        // join into a single string  the roles that the user is a member of 
        string roleData = String.Join(";", roles) ;

        // create the forms ticket that all MVC5 sites with the same machine key will pick up.
        FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1, ident.Name, DateTime.Now, DateTime.Now.AddMinutes(30), false, roleData, "/");
        string encTicket = FormsAuthentication.Encrypt(ticket);


        // add the user name first from the Principle and add Windows as this will come from Windows Auth
        roleData = ident.Name + ";" + "Windows;" + roleData;

        //use machine key to encrypt the data
        var encTicket2 = MachineKey.Protect(System.Text.Encoding.UTF8.GetBytes(roleData),
            "Microsoft.Owin.Security.Cookies.CookieAuthenticationMiddleware",
            "ApplicationCookie", "v1");

        //create a new cookie with a base64string of the encrypted bytes
        HttpCookie hc2 = new HttpCookie("cookie1", Convert.ToBase64String(encTicket2));
        hc2.Domain = ".domain.com";
        hc2.Expires = DateTime.Now.AddHours(8);
        Response.Cookies.Add(hc2);

        // NOTE: The name of the HttpCookie must match what the FormsAuth site expects.
        HttpCookie hc = new HttpCookie("cookie2", encTicket);
        hc.Domain = ".domain.com";
        hc.Expires = DateTime.Now.AddHours(8);
        Response.Cookies.Add(hc);
        // Ticket and cookie issued, now go to the FormsAuth site and all should be well.
        Response.Redirect("http://www.yoursite.com");
    }

this will create to a windows Authentication Ticket in both the forms and MVC6 method.

The string for MVC6 will look something like "John.Doe;Windows;Admin"

Then in the MVC6 startup file I have put the following code into the configure section...

        app.Use(async (context, next) =>
        {
            Logger _logger = new Logger("C:\\\\Logs\\Log.txt");
            try
            {

                var request = context.Request;
                var cookie = request.Cookies.Get("cookie1");
                var ticket = cookie.ToString();

                ticket = ticket.Replace(" ", "+");

                var padding = 3 - ((ticket.Length + 3)%4);
                if (padding != 0)
                    ticket = ticket + new string('=', padding);

                var bytes = Convert.FromBase64String(ticket);
                bytes = System.Web.Security.MachineKey.Unprotect(bytes,
                    "Microsoft.Owin.Security.Cookies.CookieAuthenticationMiddleware",
                    "ApplicationCookie", "v1");

                string ticketstring = System.Text.Encoding.UTF8.GetString(bytes);

                var ticketSplit = ticketstring.Split(';');

                var claims = new Claim[ticketSplit.Length];

                var OriginalIssuer = "";

                for (int index = 0; index != ticketSplit.Length; ++index)
                {

                    if (index == 0)
                    {
                        claims[index] = new Claim(ClaimTypes.Name, ticketSplit[index], "Windows");
                    }
                    else if (index == 1)
                    {
                        OriginalIssuer = ticketSplit[1];
                    }
                    else
                    {
                        claims[index] = new Claim(ClaimTypes.Role,ticketSplit[0], OriginalIssuer);
                    }
                }

                var identity = new ClaimsIdentity(claims, OriginalIssuer, ClaimTypes.Name,ClaimTypes.Role);

                var principal = new ClaimsPrincipal(identity);

                _logger.Write(principal.Identity.Name);

                context.User = principal;
                _logger.Write("Cookie End");
                await next();
            } catch (Exception ex)
            {
                _logger.Write(ex.Message);
                _logger.Write(ex.StackTrace);
            }
        });

This then takes the cookie and creates a new claims identity from it. I've only just finished the logic to get it working so I'm sure it can be tidied up... Just thought I would get it to you so you can see if you can get some ideas about it.

0
Roadrunner On

This is my simple code in Asp.net core mvc,hope will help:

In Startup.cs In Function ConfigureServices add services.AddAuthorization(); after service.AddMvc()

In Function Configure add code like this

app.UseCookieAuthentication(new CookieAuthenticationOptions
            {
                AuthenticationScheme = "UserLoginCookie",
                LoginPath = new PathString("/Account/Login"),
                AccessDeniedPath = new PathString("/Account/Forbidden"),
                AutomaticAuthenticate = true,
                AutomaticChallenge = true
            }); 

before app.UseMvc....

In login Method: core code like this:

     var claims = new List<Claim>()
        {
            new Claim(ClaimTypes.Name,userName here),
            new Claim("UserCodeInMyWebApp",Anything you want),
            new Claim(ClaimTypes.Role,"Admin")

        };
            var userPrincipal = new ClaimsPrincipal(new ClaimsIdentity(claims, "UserLoginClaimsIdentity"));
            //signin
            await HttpContext.Authentication.SignInAsync("UserLoginCookie", userPrincipal, new AuthenticationProperties
            {
                ExpiresUtc = DateTime.UtcNow.AddMinutes(20),
                IsPersistent = false,
                AllowRefresh = false
            });

            return RedirectToAction("AuthPage", "Home"); 

then you can access claim value by keyvalue or check if authenticated:

bool flag = User.Identity.IsAuthenticated
 ClaimsIdentity user = User.Identity as ClaimsIdentity
 user.Name or user.FindFirst(the key value string you created).Value 

and check like this:

  [HttpGet]
        [AllowAnonymous]
        public IActionResult Index()
        {
            return View();
        }

        [Authorize(Roles = "Admin")]
        [HttpGet]
        public IActionResult AuthPage()
        {
            return View();
        }

        public IActionResult About()
        {
            return View();
        }