DoIt
DoIt

Reputation: 3428

Denying Access to specific pages for a set of users in ASP.NET MVC Web API

I have developed a web API in MVC4 and I am working on authentication and authorization. I have different types of users who should have a different look at the API. So, I just created a table with users with a column IsAdmin in which few people will have it as 1 and others 0.

I have written a method to check what kind of user he is using following code

public bool IsValidAdmin(string _username, string _password)
        {
            using (var cn = new SqlConnection(@"Data Source=xyz.com;Initial Catalog=pqr;Persist Security Info=True;User ID=abc;Password=****"))
            {
                string _sql = @"SELECT [Username] FROM [dbo].[System_Users] " +
                       @"WHERE [Username] = @u AND [Password] = @p AND [IsAdmin]=1";
                var cmd = new SqlCommand(_sql, cn);
                cmd.Parameters.AddWithValue("@u",_username);
                cmd.Parameters.AddWithValue("@p", _password);

                cn.Open();
                var reader = cmd.ExecuteReader();
                if (reader.HasRows)
                {
                    reader.Dispose();
                    cmd.Dispose();
                    return true;
                }
                else
                {
                    reader.Dispose();
                    cmd.Dispose();
                    return false;
                }
            }


        }

        public bool IsValidUser(string _username, string _password)
        {
            using (var cn = new SqlConnection(@"Data Source=xyz.com;Initial Catalog=pqr;Persist Security Info=True;User ID=abc;Password=****"))
            {
                string _sql = @"SELECT [Username] FROM [dbo].[System_Users] " +
                       @"WHERE [Username] = @u AND [Password] = @p AND [IsAdmin]!=1";
                var cmd = new SqlCommand(_sql, cn);
                cmd.Parameters.AddWithValue("@u", _username);
                cmd.Parameters.AddWithValue("@p", _password);

                cn.Open();
                var reader = cmd.ExecuteReader();
                if (reader.HasRows)
                {
                    reader.Dispose();
                    cmd.Dispose();
                    return true;
                }
                else
                {
                    reader.Dispose();
                    cmd.Dispose();
                    return false;
                }
            }
        }

CONTROLLER

 [HttpPost]
        public ActionResult Login(Models.User user)
        {
            if (ModelState.IsValid)
            {
                if (user.IsValidAdmin(user.UserName, user.Password))
                {
                    FormsAuthentication.SetAuthCookie(user.UserName, user.RememberMe);
                    return RedirectToAction("Index", "Admin");
                }
                else if (user.IsValidUser(user.UserName, user.Password))
                {
                    FormsAuthentication.SetAuthCookie(user.UserName, user.RememberMe);
                    return RedirectToAction("Index", "Home");
                }
                else 
                {
                    ModelState.AddModelError("", "Login data is incorrect!");
                }
            }
            return View(user);

Admin

[OutputCache(NoStore = true, Duration = 0, VaryByParam = "None")]
        [Authorize]
        public ActionResult Index()
        {
            return View();
        }

Normal User

[OutputCache(NoStore = true, Duration = 0, VaryByParam = "None")]
      [Authorize]
      public ActionResult Index() {
      return View();
    }

It works like when a user with IsAdmin=0 logs in, it redirects him to normal page which is what I need but he can even access other pages as the user is authenticated. I think there is something I need to deal with request.IsAuthenticated in my master page as follows

Layout.cshtml

@if (Request.IsAuthenticated)
                {
                    <tr>
                    <td class="btn">@Html.ActionLink(@Html.Encode(User.Identity.Name).ToUpper()+"!!","Index","Admin")</td>
                  <td class="btn">  @Html.ActionLink("Sign Out", "Logout", "User")</td>

                        </tr>
                }
                else
                {
                     <tr>
                    <td class="User btn">
                    @Html.ActionLink("Sign In", "Login", "User")</td></tr>
                }

Now in the above cshtml in Request.IsAuthenticated it obviously returns true when a users logs in without taking into consideration whether the IsAdmin is 0 or 1 and as it is true he can access all the pages.

May I know some way to avoid that and deny access to the internal pages?

Upvotes: 0

Views: 759

Answers (2)

Jedediah
Jedediah

Reputation: 1944

You need to create a custom AuthorizeAttribute so you can apply it as a filter to specific actions in your controller that you want more granular control over.

public class CustomAuthorizeAttribute : AuthorizeAttribute
{
    public bool IsAdmin {get; set;}

    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        //Load user permissions here
        if(IsAdmin) return user.IsAdmin;
        return false;
    }
}

Then you can use it on specific actions in your controller like this:

[CustomAuthorize(IsAdmin = true)]
public ActionResult AdminOnlyAction()
{
}

If you have a lot of specific permissions you want to filter by, it might be better to just use a string for roles, and then test the user against those roles.

[CustomAuthorize(Roles = "admin,superadmin")]

Upvotes: 1

MichaC
MichaC

Reputation: 13381

MVC offers a feature which is called Filters which is meant for those kind of scenarios where you want to secure certain controller actions.

Filters can be used as attributes or as global filters.

Simply google for "MVC security filter" should give you enough information...

Implement your own security filter which checks for your custom permissions would do what you want I guess...

Upvotes: 1

Related Questions