0

I am authenticating a user:

        [Route("Login"), HttpPost, AllowAnonymous]
        public LoginViewModelResponse Login(LoginViewModelRequest data)
        {

            if(!Membership.ValidateUser(data.Username, data.Password))
            {
                return new LoginViewModelResponse
                {
                    DisplayMessage = "Invalid Username/Password!",
                    IsSuccess = false,
                    RedirectUrl = "/Home/"
                };
            }


            FormsAuthentication.SetAuthCookie(data.Username, false);
            ClaimsIdentity identity = new GenericIdentity(data.Username);


            var roles = "Administrator,User".Split(',');
           // var client = AuthorisationService.instance.GetAuthenticatedUser();// new ClientService().GetClientById(1);
            var principle = new GenericPrincipal(identity, roles);

            HttpContext.Current.User = principle;
            System.Threading.Thread.CurrentPrincipal = principle;

            if (User.IsInRole("Administrator"))
            {
                var b = 1;
            }
            return new LoginViewModelResponse
            {
                IsSuccess = true,
                DisplayMessage = "OK",
                RedirectUrl = "/Home/"
            };
        }

And the test for 'IsInRole' is working.

However, I have the following in my View (_layout), and the check for Administrator fails.

if (ViewContext.HttpContext.User.IsInRole("Administrator"))
{
   <li class="dropdown">
...

Is there something I need to do to allow the View to understand "IsInRole"?

This works:

 @if (ViewContext.HttpContext.User.Identity.IsAuthenticated == false)

But 'IsInRole' always evaluated to false.

Craig
  • 18,074
  • 38
  • 147
  • 248

1 Answers1

1

Since you set FormsAuthentication cookie by yourself, you'll need to create Principle object and assign it to current thread on every request inside AuthenticateRequest event.

Global.asax.cs

public class Global : HttpApplication
{
    protected void Application_AuthenticateRequest(object sender, EventArgs e)
    {
        HttpCookie decryptedCookie =
            Context.Request.Cookies[FormsAuthentication.FormsCookieName];
        if (decryptedCookie != null)
        {
            FormsAuthenticationTicket ticket =
                FormsAuthentication.Decrypt(decryptedCookie.Value);

            var identity = new GenericIdentity(ticket.Name);
            var roles = ticket.UserData.Split(',');
            var principal = new GenericPrincipal(identity, roles);

            HttpContext.Current.User = principal;
            Thread.CurrentPrincipal = HttpContext.Current.User;
        }
    }
}

Sign-In method

public void SignIn(string username, bool createPersistentCookie)
{
    var now = DateTime.UtcNow.ToLocalTime();
    TimeSpan expirationTimeSpan = FormsAuthentication.Timeout;

    var ticket = new FormsAuthenticationTicket(
        1 /*version*/,
        username,
        now,
        now.Add(expirationTimeSpan),
        createPersistentCookie,
        "" /*userData*/,
        FormsAuthentication.FormsCookiePath);

    var encryptedTicket = FormsAuthentication.Encrypt(ticket);

    var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, 
        encryptedTicket)
    {
        HttpOnly = true,
        Secure = FormsAuthentication.RequireSSL,
        Path = FormsAuthentication.FormsCookiePath
    };

    if (ticket.IsPersistent)
    {
        cookie.Expires = ticket.Expiration;
    }
    if (FormsAuthentication.CookieDomain != null)
    {
        cookie.Domain = FormsAuthentication.CookieDomain;
    }

    Response.Cookies.Add(cookie);
}
Win
  • 61,100
  • 13
  • 102
  • 181
  • thanks, this sounds like something I'll try. Am I setting the cookie in the wrong way? Is there a better way to achieve this? – Craig Jul 29 '17 at 00:16
  • It seems I'll need to go get my roles from the database on each authentication, and that method fires for each view it seems. – Craig Jul 29 '17 at 00:38
  • 1
    You will need to save roles inside UserData to avoid querying data for every request. I updated the answer. – Win Jul 29 '17 at 02:57
  • Thank you, @win. That's perfect. My method for using authentication is acceptable then? Thanks. – Craig Jul 29 '17 at 03:02
  • I've updated my question. My sign in method is an Api call. I don't have access to 'Response.Cookies'. Can you maybe assist with how I should change this? – Craig Jul 29 '17 at 04:35
  • [Token based authentication in Web API without any user interface](https://stackoverflow.com/q/38661090/296861) – Win Jul 29 '17 at 04:57
  • Wow, that looks like I need to use OAuth and completely rip out my current method. even though the " @if (ViewContext.HttpContext.User.Identity.IsAuthenticated == false)" works, there's no way to make the IsInRole work, using basic FormsAuthentication? – Craig Jul 29 '17 at 10:27
  • It requires few extra work at client; I do not recommend it. Ideally, we use OAuth with JWT token in ASP.NET Web API. – Win Jul 29 '17 at 13:42