简体   繁体   中英

MVC - Only allow users to edit their own data

I am writing an MVC 5 app with a relatively complicated data model.

I have Listings and Listings have photo Albums associated with them.

To get things started, I just made sure that when a user is trying to call the Edit function of a controller, that the user was the owner of the object. Like so:

     // Listing Controller
public bool VerifyOwnership(int? id)
        {
            if (id == null) return false;

            Listing listingModel = db.Listings.Find(id);
            if (listingModel == null)
            {
                return false;
            }
            else
            {
                return User.Identity.GetUserId() == listingModel.SellerID;
            }
        }

However, this check is now propagating itself throughout my code base. Since Albums are owned by Listings, this code didn't seem that terrible to me:

// AlbumController    
public ActionResult Edit(int? id, int listingId)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            Album a = db.Albums.Find(id);
            if (a == null)
            {
                return HttpNotFound();
            }

            var l = new ListingController();
            if (!l.VerifyOwnership(listingId))
                return new HttpStatusCodeResult(HttpStatusCode.Forbidden);


            ViewBag.ListingID = listingId;

            return View(a);
        }

I think I'm doing it wrong .

It seems that ideally the Album controller would not be instantiating a ListingController just to check ownership. I could copy the ownership logic out of the ListingController and paste it into the AlbumController, but now I'm copy pasting code. Yuck.

I read this article about making a custom Authorize attribute - ASP.NET MVC Attribute to only let user edit his/her own content , which seems ok except that I wasn't sure how to instantiate an ApplicationDbContext object inside the AuthorizeCore override so that I could lookup the owner of the listing and do my checks. Is it ok to just create ApplicationDbContext objects willy-nilly? Do they correlate to persistent database connections or are they an abstraction?

This is where you're going wrong....

 Album a = db.Albums.Find(id);

I could have typed in any ID and your app would go and fetch it and then perform a ownership verification which is unneeded...

Tackle the problem from the other end, what if, we were to scope our results by what the users has access to first, and then performing a search for an album within the scope of what the user has access to. Here's a few examples to give you an idea of what I mean.

db.Users.Where(user => user.Id == this.CallerId)
        .SelectMany(user => user.Albums)
        .Where(album => album.Id == "foo");

db.Albums.Where(album => album.OwnerId == this.CallerId)
         .Where(album => album.Id == "bar");

It's all going to come down to the layout of your db and the fashion in which you've mapped your entity models, but the concept is the same.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM