0

On WebForms i used to store the role in FormsAuthenticationTicket userdata, however I tried to implement the same method in mvc 5 and it did not work. For some reason

User.Identity.IsAuthenticated

this returns false

var ticket = new FormsAuthenticationTicket(
    1,
    user.Id.ToString(),
    DateTime.Now,
    DateTime.Now.AddDays(5),
    model.RememberMe,
    user.Roles.Select(c => c.Nome).FirstOrDefault(),
    FormsAuthentication.FormsCookiePath
);

// Encrypt the ticket.
string encryptedTicket = FormsAuthentication.Encrypt(ticket);
// Create the cookie.
HttpCookie authenticationCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket); // Name of auth cookie (it's the name specified in web.config) // Hashed ticket
authenticationCookie.Expires = DateTime.Now.AddDays(7);
// Add the cookie to the list for outbound response
Response.Cookies.Add(authenticationCookie);

so since this does not work i used instead

FormsAuthentication.SetAuthCookie(user.Id.ToString(), model.RememberMe);

problem with this is that it does not allow me to have an easy access to the user role so that i can do on a view

if (User.IsInRole("Admin"))

I'm trying to avoid Asp Net Identity because It takes a lot of customization and i don't need all the extra fields nor a password 'cause we authenticate with ldap.

If is there any other option please advice me.

Alexander
  • 9,104
  • 1
  • 17
  • 41
Jackal
  • 3,359
  • 4
  • 33
  • 78
  • Please share code of `Application_AuthenticateRequest` in your project or where you set `Context.User` from auth cookie – Alexander Apr 10 '19 at 14:37
  • I don't have this function implemented yet 'cause i thought it wasn't needed just for authenticating user – Jackal Apr 10 '19 at 14:52

1 Answers1

0

Forms authentication doesn't support roles by itself. So you need to set request's IPrincipal with roles manually. You can do this by "subscribing" on post authenticate event in Global.asax and update logged user information. Add the following method inside MvcApplication class in Global.asax.cs

protected void Application_OnPostAuthenticateRequest(object sender, EventArgs e)
{
    HttpCookie authCookie = Request.Cookies[FormsAuthentication.FormsCookieName];

    if (authCookie != null)
    {
        //get the forms authentication ticket
        FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);
        string userData = authTicket.UserData;
        //here we suppose userData contains roles joined with ","
        string[] roles = userData.Split(',');

        //at this point we already have Context.User set by forms authentication module
        //we don't change it but add roles
        var principal = new GenericPrincipal(Context.User.Identity, roles);

        // set new principal with roles
        Context.User = principal;
    }
}

Also you need to update login code to create proper FormsAuthenticationTicket containing roles joined with ","

var roles = user.Roles.Select(c => c.Nome);
var ticket = new FormsAuthenticationTicket(
    1,
    user.Id.ToString(),
    DateTime.Now,
    DateTime.Now.AddDays(5),
    model.RememberMe,
    string.Join(",", roles), //or you can serialize complex class as json or whatever
    FormsAuthentication.FormsCookiePath
);

Another option is to override forms authentication by adding FormsAuthentication_OnAuthenticate method in Global.asax.cs

public void FormsAuthentication_OnAuthenticate(object sender, FormsAuthenticationEventArgs args)
{
    if (FormsAuthentication.CookiesSupported)
    {
        HttpCookie authCookie = Request.Cookies[FormsAuthentication.FormsCookieName];
        if (authCookie != null)
        {
            try
            {
                //get the forms authentication ticket
                FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);
                string userData = authTicket.UserData;
                //here we suppose userData contains roles joined with ","
                string[] roles = userData.Split(',');

                //we have to create identity since it's not created yet
                var identity = new FormsIdentity(authTicket);
                var principal = new GenericPrincipal(identity, roles);

                args.User = principal;
            }
            catch (Exception e)
            {
                // Decrypt method failed.
            }
        }
    }
    else
    {
        throw new HttpException("Cookieless Forms Authentication is not " +
                                "supported for this application.");
    }
}

Both solutions are pretty similar so it's up to you to choose one.

Alexander
  • 9,104
  • 1
  • 17
  • 41