ASP.NET MVC preventing users from direct URL

2020-08-01 05:48发布

So I've created a simple "hello world" in MVC as proof of concept. The index view list some made up records that are followed by the typical "edit", "details", and "delete" ActionLinks.

However, depending on which AD group owns the record, I don't render some of those options. So for example, say I'm pulling up 5 records, and I'm a member of an Group\Role that only owns 1 of them. My Index page would look something like...

Name Price
Foo1 $10.00 Details
Foo2 $20.00 Details
Foo3 $30.00 Details | Edit | Delete
Foo4 $40.00 Details
Foo5 $50.00 Details
Foo6 $60.00 Details

This all works great. The Problem is, that as a user I can just type in a URL of /Home/Edit/Foo1 and it gives me Edit access to a record I do not own.

On first search, it would seem like I am supposed to implement something called a ChildActionOnly Attribute. From what I've read, it sounds like if my controller was set to..

[ChildActionOnly]
public ActionResult Edit(string id)
{
    return View(GetItem(id));
}

then it would not allow me to change my url and get there. However the moment I add that Attribute, the Action Link no longer works either.

@Html.ActionLink("Edit", "Edit", new { id = item.FooName })

I know I'm just missing something. I'm already implementing Authentication so unless you belong to the correct Role, it already blocks ALL access to that controller. However, once you have access... it doesn't mean you have access to change anything and everything.

5条回答
一夜七次
2楼-- · 2020-08-01 06:04

For a more flexible approach you can create a custom AuthorizeAttribute for your Controller action method and then set it like this :

[MyAuthorize]    
public ActionResult Edit(string id)
{
    var user = UserManager.FindById(User.Identity.GetUserId());
    //Check if user can access item
}

Then with an extended version of an 'AuthorizeAttribute` you could do your check there:

public class MyAuthorizeAttribute : AuthorizeAttribute
{
    // could be used to set the AD group that you are checking for
    // i.e. [MyAuthorize(strSecurityGroup="domain\group")] in the controller
    public string strSecurityGroup { get; set; }
    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        var authorized = base.AuthorizeCore(httpContext);
        if (!authorized)
        {
            return false;
        }
        var rd = httpContext.Request.RequestContext.RouteData;
        var id = rd.Values["id"];
        var userName = httpContext.User.Identity.Name;
        //Access the current record through a DataHandler class
        DataHandler dh = new DataHandler();
        // Gets a field from the database that holds the username for the owner of the record
        string createdBy = dh.GetCreatedBy(int.Parse(id.ToString()));
        bool isAuthorized = false;
        if (userName.ToString() == createdBy) isAuthorized = true;
        var User = System.Web.HttpContext.Current.User;
        if (User.IsInRole(@"domain\group")) isAuthorized = true;
        return isAuthorized;
    }
}

This is how I like to do Authorization to AD. You can create a class property in the AuthroizeAttribute to allow you to set the user group separately for each use of the attribute as well. If you are using the authorization mechanism to control actions throughout the site I think that this is cleaner than manually performing an authorization check each time.

查看更多
别忘想泡老子
3楼-- · 2020-08-01 06:11

There's no way to prevent a user to attempting to access any URL. The client (browser) merely makes a request. It is the server's responsibility to determine whether it should return something or not.

Hiding a URL to prevent access is what's called "security by obscurity" and it's basically the same as having no security at all. There is nothing so obscure that a persistent user can't figure it out. You need real security as in role or object-level permissions tied to account authentication.

For a record, you're looking at object-level permissions. The most basic implementation involves creating a foreign key on the object to a user that represents "ownership" of that object. Then, when retrieving the object, you additionally check whether the currently logged-in user is the "owner" and if not, deny access.

public ActionResult Edit(int id)
{
    var foo = db.Foos.Where(m => m.Id == id && m.OwnerId == User.Identity.GetUserId());
    if (foo == null)
    {
        return new HttpNotFoundResult();
    }

    // do whatever for authorized user
}
查看更多
乱世女痞
4楼-- · 2020-08-01 06:16

First Create a class for filter: We have to call this feature under OnActionExecuting of Action filter.

using System;
using System.Web.Mvc;
using System.Web.Routing;

namespace Customer.Filters
{
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class PreventFromUrl : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        if (filterContext.HttpContext.Request.UrlReferrer == null ||
 filterContext.HttpContext.Request.Url.Host != filterContext.HttpContext.Request.UrlReferrer.Host)
           {
            filterContext.Result = new RedirectToRouteResult(new
                                      RouteValueDictionary(new { controller = "Dashboard", action = "Index", area = "" }));
           }
    }
}
}

Then add [PreventFromUrl] attribute to the top of your action or controller:

 [PreventFromUrl]
 public ActionResult Index()
 {

 }
查看更多
老娘就宠你
5楼-- · 2020-08-01 06:26

According to documentation:

ChildActionOnlyAttribute Class

Represents an attribute that is used to indicate that an action method should be called only as a child action.

A child action method renders inline HTML markup for part of a view instead of rendering a whole view.

Any method that is marked with ChildActionOnlyAttribute can be called only with the Action or RenderAction HTML extension methods.

For more information about using attributes, see .

查看更多
Deceive 欺骗
6楼-- · 2020-08-01 06:27

Nkosi is right with his answer. To restrict access to this items you have to perform a user validation inside the Edit action. For example:

public ActionResult Edit(string id)
{
    var user = UserManager.FindById(User.Identity.GetUserId());
    //Check if user can access item
}
查看更多
登录 后发表回答