Skip to content

Instantly share code, notes, and snippets.

@alirobe
Last active November 23, 2023 02:36
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alirobe/2595fbe2d5d5fc1ef2f181d2ca18ec1f to your computer and use it in GitHub Desktop.
Save alirobe/2595fbe2d5d5fc1ef2f181d2ca18ec1f to your computer and use it in GitHub Desktop.
Secure Media Controller for Umbraco v9 Cloud
for Umbraco Cloud, get these values from Umbraco Cloud Project Manager -> Settings -> Connection Details -> Blob Storage Connection Details
"Umbraco": {
"Storage": {
"AzureBlob": {
"Media": {
"ConnectionString": "BlobEndpoint=https://ucmediastoragewelive.blob.core.windows.net/;SharedAccessSignature=[4. Shared Access Signature, without the first question mark]",
"ContainerName": "[3. Container Name GUID only, no curly braces]"
}
}
},
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.
You'll need to disable CDN cache entirely in Umbraco Cloud for this to work, otherwise I think media requests are handled by Cloudflare.
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Core.Services;
using MimeKit;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.IO;
namespace UmbracoProject.Controllers
{
public class SecureMediaController : Controller
{
private readonly IMediaService _mediaService;
private readonly IMemberService _memberService;
private readonly MediaFileManager _mediaFileManager;
public SecureMediaController(IMediaService mediaService, IMemberService memberService, MediaFileManager mediaFileManager)
{
_mediaService = mediaService;
_memberService = memberService;
_mediaFileManager = mediaFileManager;
}
public 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();
// 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
if (_mediaFileManager.FileSystem.FileExists(mediaPath)) {
var fileStreamReader = _mediaFileManager.FileSystem.OpenFile(mediaPath);
var mimeType = MimeTypes.GetMimeType(file);
return new FileStreamResult(fileStreamReader, mimeType);
}
return NotFound();
}
}
}
public void ConfigureServices(IServiceCollection services)
{
#pragma warning disable IDE0022 // Use expression body for methods
services.AddUmbraco(_env, _config)
.AddBackOffice()
.AddWebsite()
.AddComposers()
// For Umbraco Cloud:
.AddAzureBlobMediaFileSystem(options =>
{
options.ConnectionString = _config.GetValue("Umbraco:Storage:AzureBlob:Media:ConnectionString", "");
options.ContainerName = _config.GetValue("Umbraco:Storage:AzureBlob:Media:ContainerName", "");
})
.Build();
#pragma warning restore IDE0022 // Use expression body for methods
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseUmbraco()
.WithMiddleware(u =>
{
u.UseBackOffice();
u.UseWebsite();
// For Umbraco Cloud:
u.UseAzureBlobMediaFileSystem();
})
.WithEndpoints(u =>
{
u.UseInstallerEndpoints();
u.UseBackOfficeEndpoints();
u.UseWebsiteEndpoints();
// For all sites:
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