locked
How make a dynamic Authorize? RRS feed

  • Question

  • User-733224187 posted

    Hello everyone, I am doing an application from scratch and using a custom user table, I would like to know if it is possible to create authorization of the most dynamic controllers without having to put in the controller which role is allowed to access it, just like in Identity.

    My idea is to create a role and checkbox which controller can access, I searched google, but all use Identity.

    this is exemplo of role:

    https://drive.google.com/file/d/1b1FNM7PRzLgFjUK1BEpPAqAo7Wp5acga/view?usp=sharing

    Monday, August 12, 2019 5:42 PM

Answers

  • User475983607 posted

    Do you have an example of how you do it? Because I never worked without the AspNetUsers table

    The basic pattern is shown below.  The code assumes this is an MVC application (you posted in a web forms forum), you are using Cookie Authentication with your custom authentication code, you are using some kind of data access like Entity Framework.

        public class CustomAuthorize : AuthorizeAttribute
        {
            protected override bool AuthorizeCore(HttpContextBase httpContext)
            {
                var isAuthorized =  base.AuthorizeCore(httpContext);
                if (!isAuthorized)
                {
                    return false;
                }
    
                var routeData = httpContext.Request.RequestContext.RouteData;
                string action = routeData.GetRequiredString("action");
                string controller = routeData.GetRequiredString("controller");
                string area = routeData.Values["area"] as string;
    
                //Lookup the user 
                return MyCustomDbAccessLayer.IsUserAuthorized(httpContext.User.Identity.Name, action, controller);
            }
        }
    
        public class MyCustomDbAccessLayer
        {
            public static bool IsUserAuthorized(string username, string action, string controller)
            {
                //fake user lookup
                return true;
            }
        }

    Add the attribute to the controller or action that needs the custom lookup.

        [CustomAuthorize]
        public class HomeController : Controller
        {
            public ActionResult Index()
            {
                return View();
            }

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Monday, August 12, 2019 6:47 PM

All replies

  • User475983607 posted

    Sure, should we assuming this is an MVC question not Web Forms since you are asking about a controller?

    Create a custom authorize attribute that looks up what actions the user can access. 

    Monday, August 12, 2019 5:54 PM
  • User-733224187 posted

    Do you have an example of how you do it? Because I never worked without the AspNetUsers table

    Monday, August 12, 2019 6:07 PM
  • User475983607 posted

    Do you have an example of how you do it? Because I never worked without the AspNetUsers table

    The basic pattern is shown below.  The code assumes this is an MVC application (you posted in a web forms forum), you are using Cookie Authentication with your custom authentication code, you are using some kind of data access like Entity Framework.

        public class CustomAuthorize : AuthorizeAttribute
        {
            protected override bool AuthorizeCore(HttpContextBase httpContext)
            {
                var isAuthorized =  base.AuthorizeCore(httpContext);
                if (!isAuthorized)
                {
                    return false;
                }
    
                var routeData = httpContext.Request.RequestContext.RouteData;
                string action = routeData.GetRequiredString("action");
                string controller = routeData.GetRequiredString("controller");
                string area = routeData.Values["area"] as string;
    
                //Lookup the user 
                return MyCustomDbAccessLayer.IsUserAuthorized(httpContext.User.Identity.Name, action, controller);
            }
        }
    
        public class MyCustomDbAccessLayer
        {
            public static bool IsUserAuthorized(string username, string action, string controller)
            {
                //fake user lookup
                return true;
            }
        }

    Add the attribute to the controller or action that needs the custom lookup.

        [CustomAuthorize]
        public class HomeController : Controller
        {
            public ActionResult Index()
            {
                return View();
            }

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Monday, August 12, 2019 6:47 PM
  • User-733224187 posted
     [HttpPost]
            [AllowAnonymous]
            [ValidateAntiForgeryToken]
            public async Task<ActionResult> Login(UserLogin login, string ReturnUrl = "")
           {
                string message = "";
                var v = db.Users.Where(a => a.UserName == login.UserName).FirstOrDefault();
                if (v != null)
                {
                    if (!v.ConfirmarEmail)
                    {
                            Guid activationcode = v.ActivationCode;
                            string callbackUrl = await SendEmailConfirmationTokenAsync(Convert.ToString(v.UserId), v.UserName, "Confirmação de e-mail reenviada", activationcode.ToString());
                            ViewBag.Message = "Por favor, verifique seu e-mail antes de realizar o login.";
                            return View("Info");
                        
                        
                    }
    
                    if (v.IsEnabled == true)
                    {
                        return View("Lockout");
                    }
    
                    if (string.Compare(Crypto.Hash(login.Password), v.Password) == 0)
                    {
                        int timeout = login.RememberMe ? 525600 : 20; // 525600 min = 1 year
                        var ticket = new FormsAuthenticationTicket(login.UserName, login.RememberMe, timeout);
                        string encrypted = FormsAuthentication.Encrypt(ticket);
                        var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encrypted);
                        cookie.Expires = DateTime.Now.AddMinutes(timeout);
                        cookie.HttpOnly = true;
                        Response.Cookies.Add(cookie);
    
    
                        if (Url.IsLocalUrl(ReturnUrl))
                        {
                            return Redirect(ReturnUrl);
                        }
                        else
                        {
                            return RedirectToAction("Index", "Home");
                        }
                    }
    
                }
                else
                {
                    message = " E - mail e / ou senha incorreto(s).";
                }
            
            ViewBag.Message = message;
                return View();
            }         

    My login controller

    Monday, August 12, 2019 7:07 PM
  • User-2054057000 posted

    You can simply use session to store authorize values of a user, and then in your master page of the web forms, you can make the check for authentication. 

    Check: Trick – How to implement Session Authentication In ASP.NET

    Tuesday, August 13, 2019 4:59 AM
  • User-733224187 posted

    So guys I started my application using the individual user account and using Owin as security and authorization, but he was very plastered to create roles and put autorise on each controller created, so I changed the form of authentication and wanted to create this way to select the functions of each controller and add to the role more dynamically to access the functions from there.

    My form of authentication:

    <authentication mode="Forms">
          <forms cookieless="UseCookies" loginUrl="~/user/login" slidingExpiration="true"></forms>
        </authentication>

    I created a new user table and created the controller for register, login and forgotpassword

        //Registration Action
            [HttpGet]
            [AllowAnonymous]
            public ActionResult Register()
            {
                return View();
            }
            //Registration POST action 
            [HttpPost]
            [AllowAnonymous]
            [ValidateAntiForgeryToken]
            public async Task<ActionResult> Register(User user)
            {
                
    
                if (ModelState.IsValid)
                {
                   
                     var isExist = IsEmailExist(user.UserName);
                        if (isExist)
                        {
                            ModelState.AddModelError("EmailExist", "Email already exist");
                            return View(user);
                        }
                        user.ActivationCode = Guid.NewGuid();
                        user.Password = Crypto.Hash(user.Password);
                        user.ConfirmPassword = Crypto.Hash(user.ConfirmPassword);
                        user.ConfirmarEmail = false;
                        user.IsEnabled = false;
    
                        db.Users.Add(user);
                        db.SaveChanges();
                        string callbackUrl = await SendEmailConfirmationTokenAsync( user.UserName, "Por favor, confirme seu e-mail", Convert.ToString(user.ActivationCode));
                        ViewBag.Message = "Por favor, verifique seu e-mail antes de continuar.";
                        return View("Info");
                    
                    
               
                }
                
    
               
                return View(user);
    
            }
            //Verify Account  
            [AllowAnonymous]
            [HttpGet]
            public ActionResult VerifyAccount(string id)
            {
                bool Status = false;
    
                db.Configuration.ValidateOnSaveEnabled = false;
                var v = db.Users.Where(a => a.ActivationCode == new Guid(id)).FirstOrDefault();
                if (v != null)
                {
                    v.ConfirmarEmail = true;
                    db.SaveChanges();
                    Status = true;
                }
                else
                {
                    ViewBag.Message = "Requisição invalida";
                }
    
                ViewBag.Status = Status;
                return View();
            }
    
            //Login 
            [HttpGet]
            [AllowAnonymous]
            public ActionResult Login()
            {
                return View();
            }
    
            //Login POST
            [HttpPost]
            [AllowAnonymous]
            [ValidateAntiForgeryToken]
            public async Task<ActionResult> Login(UserLogin login, string ReturnUrl = "")
           {
                string message = "";
                var v = db.Users.Where(a => a.UserName == login.UserName).FirstOrDefault();
                if (v != null)
                {
                    if (!v.ConfirmarEmail)
                    {
                            Guid activationcode = v.ActivationCode;
                            string callbackUrl = await SendEmailConfirmationTokenAsync(Convert.ToString(v.UserId), v.UserName, "Confirmação de e-mail reenviada", activationcode.ToString());
                            ViewBag.Message = "Por favor, verifique seu e-mail antes de realizar o login.";
                            return View("Info");
                        
                        
                    }
    
                    if (v.IsEnabled == true)
                    {
                        return View("Lockout");
                    }
    
                    if (string.Compare(Crypto.Hash(login.Password), v.Password) == 0)
                    {
                        int timeout = login.RememberMe ? 525600 : 20; // 525600 min = 1 year
                        var ticket = new FormsAuthenticationTicket(login.UserName, login.RememberMe, timeout);
                        string encrypted = FormsAuthentication.Encrypt(ticket);
                        var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encrypted);
                        cookie.Expires = DateTime.Now.AddMinutes(timeout);
                        cookie.HttpOnly = true;
                        Response.Cookies.Add(cookie);
    
    
                        if (Url.IsLocalUrl(ReturnUrl))
                        {
                            return Redirect(ReturnUrl);
                        }
                        else
                        {
                            return RedirectToAction("Index", "Home");
                        }
                    }
    
                }
                else
                {
                    message = " E - mail e / ou senha incorreto(s).";
                }
            
            ViewBag.Message = message;
                return View();
            }                        
                 
    
            //Logout
            [Authorize]
            [HttpPost]
            public ActionResult Logout()
            {
                FormsAuthentication.SignOut();
                return RedirectToAction("Login", "Users");
            }
    
    
            [NonAction]
            public bool IsEmailExist(string emailID)
            {
               
                    var v = db.Users.Where(a => a.UserName == emailID).FirstOrDefault();
                    return v != null;
                
            }
    
            [NonAction]
    
            private async Task<string> SendEmailConfirmationTokenAsync(string userName, string subject, string activationCode, string emailFor = "VerifyAccount")
            {
                var verifyUrl = "/Users/" + emailFor + "/" + activationCode;
                var callbackUrl = Request.Url.AbsoluteUri.Replace(Request.Url.PathAndQuery, verifyUrl);
    
                if (emailFor == "VerifyAccount")
                { 
                    string body = macpartner.Resources.emailConfirmationBody;
                body = body.Replace("[link]", callbackUrl);
                await MailHelper.SendMail(userName, subject, body);
                }
                if(emailFor == "ResetPassword")
                {
                    var body = macpartner.Resources.forgotPassBody;
                    body = body.Replace("Oi[nome]", "Olá");
                    body = body.Replace("[link]", callbackUrl);
                    await MailHelper.SendMail(userName, subject, body);
                }
    
                return callbackUrl;
            }
    
            //Part 3 - Forgot Password
            [AllowAnonymous]
            public ActionResult ForgotPassword()
            {
                return View();
            }
    
            [HttpPost]
            [AllowAnonymous]
            public async Task<ActionResult> ForgotPassword(ForgotPasswordModel model)
            {
                var account = db.Users.Where(a => a.UserName == model.Email).FirstOrDefault();
                string message = "";
    
                if (account != null)
                {
    
                   
    
                   
                        string resetCode = Guid.NewGuid().ToString();
                        await SendEmailConfirmationTokenAsync(account.UserName, "IndicaMais - Cadastro de Nova Senha", resetCode, "ResetPassword");
                        account.ResetPasswordCode = resetCode;
                        db.Configuration.ValidateOnSaveEnabled = false;
                        db.SaveChanges();
                      
                    
                 
                    return RedirectToAction("ForgotPasswordConfirmation", "Users");
                }
                else
                {
                  message = "Usuário Não encontrado";
                }
                
                ViewBag.Message = message;
                return View(model);
            }
    
            //GET: /Account/ForgotPasswordConfirmation
           [AllowAnonymous]
            public ActionResult ForgotPasswordConfirmation()
            {
                return View();
            }
    
            [AllowAnonymous]
            public ActionResult ResetPassword(string id)
            {
                
                if (string.IsNullOrWhiteSpace(id))
                {
                    return HttpNotFound();
                }
    
                
                    var user = db.Users.Where(a => a.ResetPasswordCode == id).FirstOrDefault();
                    if (user != null)
                    {
                        ResetPasswordModel model = new ResetPasswordModel();
                        model.ResetCode = id;
                        return View(model);
                    }
                    else
                    {
                        return HttpNotFound();
                    }
                
            }
    
            [HttpPost]
            [AllowAnonymous]
            [ValidateAntiForgeryToken]
            public ActionResult ResetPassword(ResetPasswordModel model)
            {
                var message = "";
                if (ModelState.IsValid)
                {
                    
                        var user = db.Users.Where(a => a.ResetPasswordCode == model.ResetCode).FirstOrDefault();
                        if (user != null)
                        {
                            user.Password = Crypto.Hash(model.Password);
                            user.ResetPasswordCode = "";
                            db.Configuration.ValidateOnSaveEnabled = false;
                            db.SaveChanges();
                         return RedirectToAction("ResetPasswordConfirmation", "Users");
                    }
                    
                }
                else
                {
                    message = "Erro na requisição";
                }
                ViewBag.Message = message;
                return View(model);
            }
    
            // GET: /Account/ResetPasswordConfirmation
            [AllowAnonymous]
            public ActionResult ResetPasswordConfirmation()
            {
                return View();

    But I dont know how make this, i want create a new table for roles and permission

    Tuesday, August 13, 2019 12:02 PM
  • User475983607 posted

    But I dont know how make this, i want create a new table for roles and permission

    It seems your requirement scope is expanding.  So you're new question is how to design a schema to support roles and permissions.  I'll assume permissions are areas, controllers, and actions.

    Create Role, Permission, and RolePermissions tables.  At a minimum,  the Role table contains roles.  The Permission table contains area, controller, and action columns.  The RolePermissions table relates the Role and Permission using the primary key of the Role and Permission table.

    Tuesday, August 13, 2019 12:57 PM
  • User-733224187 posted

    I need your helpe, because I don't know how to make the permission table.

    Got an example or link from a question like mine?

    Tuesday, August 13, 2019 5:19 PM
  • User475983607 posted

    ecocash

    I need your helpe, because I don't know how to make the permission table.

    Got an example or link from a question like mine?

    Can you clarify?  You do not know how to write a script to create a table or implement a code first migration or you don't know what goes in the permissions table?

    Regardless, yours is a custom requirements.  It is up to you to come up with a design and write code that meets your, currently unknown, requirements.  Or do an internet search to fins something similar.  There's not much we can do as you have no clearly explained what a permission is in your application.

    Tuesday, August 13, 2019 5:39 PM
  • User-733224187 posted

    I'm sorry, my question in creating the permission table is how it will handle actions and controls, in the image I put the idea and link a user to a role, type Admin, Support, Consultant and client and in that role select which views he can access, for example the Consultant User, can access the client users and access the detail and edit but can not delete, but when we start our project we use the Identity to generate the papers, but over time it was very limited, so beginning from scratch using MVC and form as authentication,The closest to my idea I found was core and uses Identity as a form of authentication.

    link : https://www.codeproject.com/Articles/1248792/Dynamic-Role-Based-Authorization-in-ASP-NET-Core

    Tuesday, August 13, 2019 6:12 PM
  • User475983607 posted

    Identity already has this feature.  The feature is called Claims.  Claims further define user information.

    Anyway, I assume you found a solution in the Code Project tutorial?  Also, you posted this question in an ASP.NET Web Forms forum and now it seems you have working on an ASP.NET Core application.  My example above is for MVC...  Keep in mind it is very difficult to provide a solution when we don't have the subject. 

    Tuesday, August 13, 2019 6:59 PM