tags:

views:

212

answers:

5

I have an ASP.NET application. I want users to be able to upload documents. Where in the file system should I store those documents? Users should be able to upload them and see the hyperlinks to them on the site, but UserA should not be able to see UserB's documents, but the administrator role should be able to see all of them.

I'm assuming I don't want to upload them to a folder with my web application because then the web server can serve them up directly. I don't want to store the file in the database, but I can store file paths in the database.

Somebody please give me some best practices. Thanks!

A: 

You probably want a folder structure with one folder per user. You could write your own CreateFolder() method that after creating the folder adds a web.config file with authorization rules, letting only the user and administrators access it. That way, users can only access their own files, but admins can access all.

EDIT: For clarification - I am assuming that you are using the ASP.NET Membership features (although not necessarily exactly as is), which lets you put individual web.config files in a directory with the nodes shown below to control access.

<configuration>
  <system.web>
    <authorization>
      <allow roles="admin" />
      <allow users="TomasLycken" />
      <deny users="*" />
    </authorization>
  </system.web>
</configuration>
Tomas Lycken
But where would this file structure be located? In the root of my website? Would it be a better process to store it where the web server can't serve it and programatically control displaying it? I'm asking this because we will probably try to use the same approach with our PHP and ASP sites.
Mike C.
I would have it within the site, but that's because I generally find locating files on the file system outside of the web site to be a rather tedious task. Not that it's really that difficult, but it's very rarely clean... But I think a generic handler (see my other response) is what you're looking for. In classic ASP and PHP cases, you want the file directories outside of the site, to make sure no access is possible (that is possible, but not necessary, with ASP.NET).
Tomas Lycken
I don't think that having a separate folder per user is smart solution. Then you'll end up having lots of folders and what's really bad is that you'll need to update you web.config every time there's new user/folder created. I could imagine what size this config file will be eventually.
bychkov
@bychkov - I believe Tomas recommended putting a web.config file in every folder.
Mike C.
@Mike C. - Yeah I somehow missed that part of the message. Still having separate config files for every user is quite messy and not flexible solution.
bychkov
And that would be why I submitted the other alternative solution. Feel free to vote up and down as you please =)
Tomas Lycken
File.Save ( Server.MapPath("/upload/") )Works on virtual directories also, so you can put it anywhere you like
Chad Grant
A: 

Another way of doing it, is to place all the files in one place, to which you statically allow no access to anyone, and then have a generic handler (.ashx) which serves the files after looking up url and permissions from the database. This is probably a cleaner approach, and it will also take less space seeing as you won't have tons of web.config files laying around...


Note: I purposely posted this as a separate answer, so you can mark the solution you prefer as your answer and ignore the other one.

Tomas Lycken
I will have to research the handlers. I've never used them before.
Mike C.
Handlers are very similar to the pages but have shorter list of events to handle and better control over response.
bychkov
I think this is probably the way I would go. However, I would like to try to find a solution that would work for PHP, ASP, and ASP.NET. I would hate to have three different solutions to the same problem.
Mike C.
A: 

I have implemented solution like this. I store files in the protected (via web.config section) folder within the website, but instead of real file names I used guids. I also had a database that mapped guids to real names and had some extra information like file size, type etc. In your case this information could also contain name of the user that uploaded the file. To download the file I implemented HTTP handler that would get a guid parameter and based on the file type set appropriate HTTP header and write the content of the file into response. Before I write file to the response I also check permissions for the current user. Then I have a page that render a list of file names as hyperlinks that point to this HTTP handler with guid parameter that correspond to particular file in the protected folder. For upload I used very nice SlickUpload control: http://krystalware.com/Products/SlickUpload/

bychkov
A: 

You can create a virtual directory adjacent (as a sibling) to the root of your website in IIS this does a couple of things 1) it prevents users from accessing the files directly by guessing the file location, 2) you can point the virtual directory to any location you wish, 3) with directory browsing turned off you can prevent anyone from seeing the structure. You can then store the paths in a database further removing the actual structure from the clients.

Jeremy
Jeremy, I don't understand how #1 is accomplished.
Mike C.
+2  A: 

Depending on the size of the files, one options would be to store the files outside the web root so no one could hot-link to them, then, as has been suggested, produce a page that takes some arguments and Response.WriteFile() from said directory.

If the files are large you might want to use Response.TransmitFile to save on some memory on the server.

From an implemenetation point of view, I would probably store the real name of the file in the database to avoid naming collisions and save the files on disk renamed to something like a GUID or just an integer ID taken from the database table.

Then when you write the file to the output stream you can use a content disposition header to rename the file back to the original name.

HTH!

Greg B
Thanks!! I'm hoping to jump into it next week.
Mike C.
This is the method I've used and recommend.
Bryan