MVC 3 Authorize custom roles

2019-05-11 08:15发布

问题:

I am new MVC 3 user and I am trying to make admin through SQL database. First of all, I have Customer entity and admin can be defined through admin field which is boolean type in Customer entity. I want to make to access admin only in Product page, not normal customer. And I want to make [Authorize(Roles="admin")] instead of [Authorize]. However, I don't know how can I make admin role in my code really. Then in my HomeController, I written this code.

public class HomeController : Controller
{

    [HttpPost]
    public ActionResult Index(Customer model)
    {
        if (ModelState.IsValid)
        {
            //define user whether admin or customer
            SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["rentalDB"].ToString());
            String find_admin_query = "SELECT admin FROM Customer WHERE userName = '" + model.userName + "' AND admin ='true'";
            SqlCommand cmd = new SqlCommand(find_admin_query, conn);
            conn.Open();
            SqlDataReader sdr = cmd.ExecuteReader();
            //it defines admin which is true or false
            model.admin = sdr.HasRows;
            conn.Close();

            //if admin is logged in
            if (model.admin == true) {
                Roles.IsUserInRole(model.userName, "admin"); //Is it right?
                if (DAL.UserIsVaild(model.userName, model.password))
                {
                    FormsAuthentication.SetAuthCookie(model.userName, true);
                    return RedirectToAction("Index", "Product");
                }
            }

            //if customer is logged in
            if (model.admin == false) {
                if (DAL.UserIsVaild(model.userName, model.password))
                {
                    FormsAuthentication.SetAuthCookie(model.userName, true);                   
                    return RedirectToAction("Index", "Home");
                }
            }
                ModelState.AddModelError("", "The user name or password is incorrect.");
        }
        // If we got this far, something failed, redisplay form
        return View(model);
    }

And DAL class is

 public class DAL
{
    static SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["rentalDB"].ToString());

    public static bool UserIsVaild(string userName, string password)
    {
        bool authenticated = false;
        string customer_query = string.Format("SELECT * FROM [Customer] WHERE userName = '{0}' AND password = '{1}'", userName, password);      
        SqlCommand cmd = new SqlCommand(customer_query, conn);
        conn.Open();
        SqlDataReader sdr = cmd.ExecuteReader();
        authenticated = sdr.HasRows;
        conn.Close();
        return (authenticated);
    }
}

Finally, I want to make custom [Authorize(Roles="admin")]

[Authorize(Roles="admin")]
public class ProductController : Controller
{
  public ViewResult Index()
    {
        var product = db.Product.Include(a => a.Category);
        return View(product.ToList());
    }
}

These are my source code now. Do I need to make 'AuthorizeAttribute' class? If I have to do, how can I make it? Could you explain to me? I cannot understand how to set particular role in my case. Please help me how can I do. Thanks.

回答1:

Your Role.IsInRole usage isn't correct. Thats what the [Authorize(Roles="Admin")] is used for, no need to call it.

In your code you are not setting the roles anywhere. If you want to do custom role management you can use your own role provider or store them in the auth token as shown here:

http://www.codeproject.com/Articles/36836/Forms-Authentication-and-Role-based-Authorization note the section:


// Get the stored user-data, in this case, user roles
            if (!string.IsNullOrEmpty(ticket.UserData))
            {
                string userData = ticket.UserData;
                string[] roles = userData.Split(',');
                //Roles were put in the UserData property in the authentication ticket
                //while creating it
                HttpContext.Current.User = 
                  new System.Security.Principal.GenericPrincipal(id, roles);
            }
        }


However an easier approach here is to use the built in membership in asp.net. Create a new mvc project using the 'internet application' template and this will all be setup for you. In visual studio click on the "asp.net configuration" icon above solution explorer. You can manage roles here and assignment to roles.



回答2:

I know this question is a bit old but here's how I did something similar. I created a custom authorization attribute that I used to check if a user had the correct security access:

[System.AttributeUsage(System.AttributeTargets.All, AllowMultiple = false, Inherited = true)]
public sealed class AccessDeniedAuthorizeAttribute : AuthorizeAttribute
{
    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        base.OnAuthorization(filterContext);

        // Get the roles from the Controller action decorated with the attribute e.g.
        // [AccessDeniedAuthorize(Roles = MyRoleEnum.UserRole + "," + MyRoleEnum.ReadOnlyRole)]
        var requiredRoles = Roles.Split(Convert.ToChar(","));

        // Get the highest role a user has, from role provider, db lookup, etc.
        // (This depends on your requirements - you could also get all roles for a user and check if they have the correct access)
        var highestUserRole = GetHighestUserSecurityRole();

        // If running locally bypass the check
        if (filterContext.HttpContext.Request.IsLocal) return;

        if (!requiredRoles.Any(highestUserRole.Contains))
        {
            // Redirect to access denied view
            filterContext.Result = new ViewResult { ViewName = "AccessDenied" };
        }
    }
}

Now decorate the Controller with the custom attribute (you can also decorate individual Controller actions):

[AccessDeniedAuthorize(Roles="user")]
public class ProductController : Controller
{
    [AccessDeniedAuthorize(Roles="admin")]
    public ViewResult Index()
    {
        var product = db.Product.Include(a => a.Category);
        return View(product.ToList());
    }
}