Protect media items
One of my last projects required some media to be protected under a login, to ensure authorized access to confidential resources. Umbraco (v7.13) does not offer this feature built-in, but only as a commercial plugin. Since I didn’t want to use the provided plugin I decided to create my own custom auth logic.
In this scenario media items (files, folders and images) can only either be protected or public, since I didn’t need role based access. If this is your case, you can easily extend this approach. After protection, if an unauthorized user tries to access a protected media it gets redirected to the login screen.
Updating the media document type
As first action you need to update the document types of folders, files and images to include a checkbox indicating if that media should be protected or not (if you need role-based auth here you can add a role picker). Just go in Settings -> Media Types -> [File | Folder | Image]
and update each of doc types or, better, create a new document type named ProtectedMedia
that has a single boolean property named isAuthRequired
and make other document types inherit from it, with the build-in composition tab.
Overriding default media controller
Now we need to intercept every media request, which are routed under /media/{id}/{filename}
, in order to check if the requested media is protected with authentication or not.
To catch this route we need to override the Umbraco default media controller with our own custom controller and tell Umbraco to route each media request against our new controller.
Create the new controller
The IsProtectedMedia()
is a custom extension method the simply checks if the media has the isAuthRequired
property defined in the above section setted to true
. In my case I also inserted in that method some logic to protect a folder and all its children without the need of checking explicitly each child. So I assume that if the isAuthRequired
property is checked in a folder, also all its content is protected.
Route each media request to our new controller
Issues with ImageProcessor
If you are using ImageProcessingModule
, which is used by default if your are using the image cropper, images request will not be routed to the media controller because they are handled differently. To catch also these request we need to register another handler for the ImageProcessingModule.ValidatingRequest()
hook.
Video media items
This should be enough to protect media items, but it introduces an issue with the streaming of video. The FileStreamResult
that we used above to return the media does not support by default the HTTP Range requests. From the docs:
HTTP range requests allow to send only a portion of an HTTP message from a server to a client. Partial requests are useful for large media or downloading files with pause and resume functions, for example.
In order to be able to stream a video in iOS device you are asked to support these partial requests, or the video won’t simply work on these i-device (Safari desktop included!). To add support to partial requests you need to intercept video request (eg: from file extension) in the MediaController
before returning the FileStreamResult
and construct a partial response with the requested bytes. You can use this solution, taken from here:
Call it from the MediaController
before returning the FileStreamResult
, and pass the current HttpContext
and the mediaPath
:
Conclusion
This completes the protection of media items in Umbraco. This solution works also in Umbraco Cloud (tested in v7.13).