0

I'm saving User's images (let's say Avatar) from input form to e.g

C:\server_folder\

with random name e.g xcvdfgdfg.jpeg and store path to it in db.

While loading User's profile e.g First name, second name... I'd want to include that image.

Seems like easy task - I'm just gonna use

_ < img src="@Model.AvatarPath">

But it doesn't work - Image is not being rendered but I can access it when I enter that url manually, meanwhile when I save that image in folder

wwwroot/images

then it works properly with path:

_< img src="~/images/xcvdfgdfg.jpeg" alt="Smiley face"/>

So, basically I'd want to relocate folder

wwwroot/images

to

C:\server_folder

Additionally how can I prevent people from accessing those files if they know url?

Joelty
  • 1,751
  • 5
  • 22
  • 64
  • You are storing Users Avatar on His own local machine. How will you control him from deleting the file? You should upload the image file to Server and store at server side. In DB (as Base64 string) or Server web directory (static folders). Your Path should reflect the URL to ths image file on server. – Prateek Shrivastava Oct 18 '18 at 09:06
  • @PrateekShrivastava I'd want to save it on Application's machine on disk ``C:\`` – Joelty Oct 18 '18 at 09:07
  • @Amadan So, how can I add location ``C:\userfiles`` to my application - as something like ``wwwroot/images``? – Joelty Oct 18 '18 at 09:09
  • Web Browsers cannot access Files from System Disks - no matter they know the exact path. This is a Security feature and you can't do so. Imagine a hacker scripts to delete stuff from C:\Windows\ folder. Or Copies malwares to your system. Browser prevent access to File System (unless its a File Browser/Save File Dialog) – Prateek Shrivastava Oct 18 '18 at 09:09
  • @PrateekShrivastava I expressed myself wrong. ``C:\usersFiles`` is server's location, not user's. Let's rename it to something more obvious ``C:\server_folder``. I want to store images as a files on server and then return them just like .css .js .bmp files – Joelty Oct 18 '18 at 09:12
  • What path is IIS mapped to (i.e. what folder has your website code in it)? – mjwills Oct 18 '18 at 09:14
  • Cool - So you need to configure that folder as web hosted folder. Check how can you do so on the WebServer that you are using (IIS or similar). Ideally, have a folder in the Web Application Directory like public/resources/avatars or so. Upload images to this location and href to ./resources/avatars/@Model-blah-blah.jpg – Prateek Shrivastava Oct 18 '18 at 09:15
  • @PrateekShrivastava how can I prevent people from accessing those files if they do know URL? Is it possible to hide it behind ``[Authorize]`` controller? – Joelty Oct 18 '18 at 09:19
  • well you can't as the name imply URL, what you can do is prevent access to C:\server_folder but if your server is rendering anything from C:\server_folder\myavatar.jpeg nothing stops them from hitting www.myapplication.com/images/myavatar.jpeg direct and seeing the image – Jack M Oct 18 '18 at 09:24
  • By all means the access is readonly. So they cannot change/update the server folder content. Secondly, you can use "Virtual Paths" - which is like when you register the static content folder (say: C:\server_folder\avatars\) you can specify a Handy name for it like public/avatars. (This is part of the Static Content registering Method/process). Now your html will look to b pointing to a folder public/avatars/img123.jpg but that is not a folder on the server. The WebServer knows how to map this virtual path to real path. That way no one can reach your images. – Prateek Shrivastava Oct 18 '18 at 09:28
  • @JackM What if I just convert that file to byte[] on server side and instead of returning file, then I'd just return byte[] with ``"data:image/png;base64,"``? – Joelty Oct 18 '18 at 09:34
  • I think that wouldn't change anything. there is an answer here though https://stackoverflow.com/questions/186062/can-an-asp-net-mvc-controller-return-an-image/1349318#1349318 and you can add an authorize to the action – Jack M Oct 18 '18 at 09:51

3 Answers3

0

Use this to configure/setup Static Content Directory in IIS

IIS7, web.config to allow only static file handler in directory /uploads of website

Prateek Shrivastava
  • 1,877
  • 1
  • 10
  • 17
  • I'm not using IIS, so I gotta check how to do that on Kestrel – Joelty Oct 18 '18 at 09:18
  • 1
    For Kestrel - it should be a method call that you can use during Bootstrap/Startup. May be: app.UseStaticFiles(); or .UseWebRoot("C:\\wwwroot") See this: https://stackoverflow.com/questions/46161382/asp-net-core-2-0-kestrel-not-serving-static-content – Prateek Shrivastava Oct 18 '18 at 09:23
0

As Prateek mentions I'd use the UseStaticFiles extension method. You can put it in the Configure method of your Startup.cs. You can use multiple of those as long as there are no conflicting RequestPath properties

app.UseStaticFiles(); // For the wwwroot folder

app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = new PhysicalFileProvider("C:\server_folder")),
    RequestPath = "/images"
});

Taken from (adapted): Microsoft Docs

hyvte
  • 183
  • 1
  • 10
  • But what about validation whether user has rights to those files? – Joelty Oct 22 '18 at 11:09
  • You could put your own middleware in the pipeline before the `UseStaticFiles` which does the validation. Or you make a separate controller and return the image (read from disk). With the controller you could use the `[Authorize]` attribute. Anyways more [here](https://stackoverflow.com/questions/36775942/how-do-i-serve-static-files-only-to-authorized-users) – hyvte Oct 23 '18 at 12:43
-1

Here's how I solved that:

I'm returning Model which's one of properties is Base64 string.

public class UserProfile
{
    (...)
    public string ImageBase64 { get; set; }
}

I'm converting File to Base64 with this method:

private string ToBase64(string path)
{
    if (System.IO.File.Exists(path))
    {
        Byte[] bytes = System.IO.File.ReadAllBytes(path);
        return Convert.ToBase64String(bytes);
    }
    return "";
}

and then in HTML

< img src="data:image/png;base64, @item.Base64" alt="test />

Joelty
  • 1,751
  • 5
  • 22
  • 64
  • Another approach to consider (to get better caching options etc) would be to add an endpoint to your website. For example `GetMyImage`. Then use `< img src="http://yourwebsite.com/getmyimage" alt="test />` `GetMyImage` will do something similar to https://stackoverflow.com/questions/40794275/return-jpeg-image-from-asp-net-core-webapi/. This means, for example, if you need the image in your page twice you don't need to include the (large!) base64 version of it twice in the page. – mjwills Oct 18 '18 at 10:43
  • nothing here stop unauthorized user from accessing the images – Jack M Oct 19 '18 at 07:03
  • @JackM I'm planning to add validation to controller that returns those base64, so I think it'll be safe because User cannot just escape out of application folder and freely check my disks files. e.g: ``localhost:12345/../../../secret_folder`` – Joelty Oct 22 '18 at 11:06