Skip to content

Instantly share code, notes, and snippets.

@alirobe
Last active November 23, 2023 02:36
Show Gist options
  • Select an option

  • Save alirobe/2595fbe2d5d5fc1ef2f181d2ca18ec1f to your computer and use it in GitHub Desktop.

Select an option

Save alirobe/2595fbe2d5d5fc1ef2f181d2ca18ec1f to your computer and use it in GitHub Desktop.
Secure Media Controller for Umbraco v9 Cloud
Original code here: https://giacomodeliberali.com/blog/umbraco-protect-media-items
This is the result of me modifying things and trying to get it working in Umbraco 9 cloud.
One major difference: I decided to redirect all ~/media folder requests to /secure, and handle it there.
This is because I had trouble hijacking /media in umbraco cloud, probably due to my own ignorance.
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ViewEngines;
using Microsoft.Extensions.Logging;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Web;
using Umbraco.Cms.Web.Common.Controllers;
using MimeKit;
using Microsoft.AspNetCore.Hosting;
using System.IO;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Security;
using Umbraco.Cms.Web.Common.Security;
using System.Threading.Tasks;
namespace UmbracoProject.Controllers
{
/// <summary>
/// Handles all request to media items in order to check is they need auth or not
/// </summary>
public class SecureMediaController : Controller
{
private readonly IMediaService _mediaService;
private readonly IMemberService _memberService;
private readonly IHostingEnvironment _hostingEnvironment;
public SecureMediaController(IMediaService mediaService, IMemberService memberService, IHostingEnvironment hostingEnvironment)
{
_mediaService = mediaService;
_memberService = memberService;
_hostingEnvironment = hostingEnvironment;
}
/// <summary>
/// The action called when processing a media request
/// </summary>
/// <param name="id">The umbraco file id</param>
/// <param name="file">The umbraco filename with extension</param>
public async Task<ActionResult> Index(string id, string file)
{
// reconstruct the media path and retrieve it
string mediaPath = $"/media/{id}/{file}";
var media = _mediaService.GetMediaByPath(mediaPath);
if (media == null)
return NotFound();
// N.B. THE FOLLOWING BIT IS UNTESTED AS I AM DOING SOMETHING ELSE HERE
if (media.IsProtectedMedia())
{
// check if the user has right roles
if (!this.HttpContext.User.IsInRole("YourRole"))
{
// otherwise redirect
return Redirect(Defaults.LoginRoute);
}
}
// UNTESTED BIT ENDS
var mediaLocation = Path.Combine(_hostingEnvironment.WebRootPath + mediaPath);
var fileStreamReader = new StreamReader(mediaLocation);
return new FileStreamResult(fileStreamReader.BaseStream, MimeKit.MimeTypes.GetMimeType(file));
}
}
}
// add the u.EndpointRouteBuilder.MapControllerRoute bit
app.UseUmbraco()
.WithMiddleware(u =>
{
u.UseBackOffice();
u.UseWebsite();
})
.WithEndpoints(u =>
{
u.UseInstallerEndpoints();
u.UseBackOfficeEndpoints();
u.UseWebsiteEndpoints();
u.EndpointRouteBuilder.MapControllerRoute(
"SecureMediaRoute",
"secure/{id?}/{file?}",
new {
controller = "SecureMedia",
action = "Index"
}
);
});
<?xml version="1.0" encoding="utf-8"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<location>
<system.webServer>
<rewrite xdt:Transform="InsertIfMissing">
<rules>
<rule xdt:Locator="Match(name)" xdt:Transform="InsertIfMissing" name="lock media folder" stopProcessing="true">
<match url="^media/(.*)" />
<action type="Redirect" url="/secure/{R:1}" appendQueryString="true" redirectType="Temporary" />
</rule>
</rules>
</rewrite>
</system.webServer>
</location>
</configuration>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment