0
votes

I want to implement my custom authorization, I wonder what is wrong with my code even I got the user credentials correctly it still redirects me to my Login Method, please see the code below

Edit: I have successfully implemented the Authorize Attribute with Roles, for future readers please see code below

Login Controller

[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Login (AdminViewModels.Login viewModel, string returnURL)
{
    if (!ModelState.IsValid)
    {
        return View(viewModel);
    }
    PasswordHasher passwordVerify = new PasswordHasher();
    var query = (from acc in db.accounts.Where(x => x.username == viewModel.Username)
                select new { acc.username, acc.password}).FirstOrDefault();
    if (query != null)
    {
        if (ModelState.IsValid)
        {
            var result = passwordVerify.VerifyHashedPassword(query.password, viewModel.Password);
            switch (result)
            {
                case PasswordVerificationResult.Success:
//set forms ticket to be use in global.asax
                    SetupFormsAuthTicket(viewModel.Username, viewModel.rememeberMe);
                    return RedirectToLocal(returnURL);
                case PasswordVerificationResult.Failed:
                    ModelState.AddModelError("", "Wrong Username or Password");
                    return View(viewModel);
            }
        }
    }
    return View(viewModel);
}

Forms Auth Ticket

private account SetupFormsAuthTicket(string userName, bool persistanceFlag)
{
    account user = new account();
    var userId = user.id;
    var userData = userId.ToString(CultureInfo.InvariantCulture);
    var authTicket = new FormsAuthenticationTicket(1, //version
                        userName, // user name
                        DateTime.Now,             //creation
                        DateTime.Now.AddMinutes(20), //Expiration
                        persistanceFlag, //Persistent
                        userData);

    var encTicket = FormsAuthentication.Encrypt(authTicket);
    Response.Cookies.Add(new HttpCookie(FormsAuthentication.FormsCookieName, encTicket));
    return user;
}

Global.asax

protected void Application_PostAuthenticateRequest(Object sender, EventArgs e)
    {
        if (FormsAuthentication.CookiesSupported == true)
        {
            if (Request.Cookies[FormsAuthentication.FormsCookieName] != null)
            {
                try
                {
                    //take out user name from cookies              
                    string username = FormsAuthentication.Decrypt(Request.Cookies[FormsAuthentication.FormsCookieName].Value).Name;
                    string[] roles = null;

                    trainingEntities db = new trainingEntities();
                    //query database to get user roles
                    var query = (from acc in db.account_roles where acc.account.username == username select acc.role.role_name).ToArray();
                    roles = query;

                    //Let us set the Pricipal with our user specific details
                    HttpContext.Current.User = new System.Security.Principal.GenericPrincipal(
                      new System.Security.Principal.GenericIdentity(username, "Forms"), roles);
                }
                catch (Exception)
                {
                    //somehting went wrong
                }
            }
        }
    } 

Now you can use [Authorize(Roles = "Admin")]

to any action method or on top of controller

2
What does return userrole.role_name; in ReturnUserRole() actually return? - user3559349
it should return the role of the specified username. - Nevi
Curious why you have select new {acc.account.username, acc_roles.role.role_name} but only use the second value. And then why you have var roles = string.Join(...) when you only returning a single value. - user3559349
i have updated my code.. - Nevi
That makes more sense :) Do you actually hit the var roles = ReturnUserRole(..) line? And what is the value of this.UserRole? - user3559349

2 Answers

0
votes

I have successfully implemented the Authorize Attribute with Roles, for future readers please see code below.

Login Controller

            [HttpPost]
            [AllowAnonymous]
            [ValidateAntiForgeryToken]
            public ActionResult Login (AdminViewModels.Login viewModel, string returnURL)
            {
                if (!ModelState.IsValid)
                {
                    return View(viewModel);
                }
                PasswordHasher passwordVerify = new PasswordHasher();
                var query = (from acc in db.accounts.Where(x => x.username == viewModel.Username)
                            select new { acc.username, acc.password}).FirstOrDefault();
                if (query != null)
                {
                    if (ModelState.IsValid)
                    {
                        var result = passwordVerify.VerifyHashedPassword(query.password, viewModel.Password);
                        switch (result)
                        {
                            case PasswordVerificationResult.Success:
                               //set forms ticket to be use in global.asax
                                SetupFormsAuthTicket(viewModel.Username, viewModel.rememeberMe);
                                return RedirectToLocal(returnURL);
                            case PasswordVerificationResult.Failed:
                                ModelState.AddModelError("", "Wrong Username or Password");
                                return View(viewModel);

                        }
                    }
                }
                return View(viewModel);

            }

FormsAuthTicket

  private account SetupFormsAuthTicket(string userName, bool persistanceFlag)
    {
        account user = new account();
        var userId = user.id;
        var userData = userId.ToString(CultureInfo.InvariantCulture);
        var authTicket = new FormsAuthenticationTicket(1, //version
                            userName, // user name
                            DateTime.Now,             //creation
                            DateTime.Now.AddMinutes(20), //Expiration
                            persistanceFlag, //Persistent
                            userData);

        var encTicket = FormsAuthentication.Encrypt(authTicket);
        Response.Cookies.Add(new HttpCookie(FormsAuthentication.FormsCookieName, encTicket));
        return user;
    }

Global.asax

protected void Application_PostAuthenticateRequest(Object sender, EventArgs e)
    {
        if (FormsAuthentication.CookiesSupported == true)
        {
            if (Request.Cookies[FormsAuthentication.FormsCookieName] != null)
            {
                try
                {
                    //take out user name from cookies              
                    string username = FormsAuthentication.Decrypt(Request.Cookies[FormsAuthentication.FormsCookieName].Value).Name;
                    string[] roles = null;

                    trainingEntities db = new trainingEntities();
                    //query database to get user roles
                    var query = (from acc in db.account_roles where acc.account.username == username select acc.role.role_name).ToArray();
                    roles = query;

                    //Let us set the Pricipal with our user specific details
                    HttpContext.Current.User = new System.Security.Principal.GenericPrincipal(
                      new System.Security.Principal.GenericIdentity(username, "Forms"), roles);
                }
                catch (Exception)
                {
                    //somehting went wrong
                }
            }
        }
    } 

Now you can use [Authorize(Roles = "Admin")]

to any action method or on top of controller

-1
votes

as I see in ControllerLogin attribute it is now being applied in a variable, when it should be applied to a method or a class

 [CustomAuthorization(UserRole="Admin")]
 // GET: Manage
 private trainingEntities db = new trainingEntities();
 public ActionResult Index()
 {
     return View();
 }


Private trainingEntities dB = new TrainingEntities();

[CustomAuthorization(UserRole="Admin")]
Public ActionResult Index()
{
   //yourcode
}