Implementing a CDN setup in Sitecore is really easy. Basically you just ned to set the setting Media.AlwaysIncludeServerUrl to true and include the base address to your CDN of choice in the Media.MediaLinkServerUrl setting.
Brian Pedersen from Pentia has a rally good article on setting up Sitecore with Azure CDN here https://briancaos.wordpress.com/2017/06/16/sitecore-media-library-integration-with-azure-cdn-using-origin-pull/.
However this can get a bit trickier if your media library contains media that is protected from anonymous access. If you protect a media item from anonymous access of course Sitecore will not allow anonymous users to access the media so in this regard everything works as expected. However if a user is logged in she will be able to access the media and it will be served through the CDN and because of this the media is now moved to the CDN and is publicly available to anyone who has the url. So if the user shares the link with a user that shouldn’t have access to the media then nothing will stop them from accessing it through the CDN.
The above case may be a theoretical edge case, however in my particular case we also have an internal web crawler that indexes our sites for the site search and when users search our websites we also want them to be able to search our locked media documents and therefore we have configured our web crawler to log into the site before crawling. However with the built-in CDN support in Sitecore this would mean that all the media would be served through the CDN and the CDN urls would end up in the search results and be available to all users regardless of whether they are logged in or not.
So how to solve this? Well the easiest solution seems to be to simply circumvent the CDN and ensure that locked media is always served directly from Sitecore where we will be able to handle access rights correctly.
To acheive this we will have to hook into the process responsible for creating the CDN urls and that means that we will have to create our own media provider in Sitecore.
using Sitecore; using Sitecore.Data.Items; using Sitecore.Resources.Media; using Sitecore.Security.Accounts; namespace TGC.Feature.Media { public class MediaProvider : Sitecore.Resources.Media.MediaProvider { public override string GetMediaUrl(MediaItem item, MediaUrlOptions options) { if (UseCdn(options) && !AnonymousUserHasAccess(item)) DisableCdn(options); return base.GetMediaUrl(item, options); } private bool UseCdn(MediaUrlOptions options) { return !string.IsNullOrEmpty(options.MediaLinkServerUrl) && options.AlwaysIncludeServerUrl; } private bool AnonymousUserHasAccess(CustomItemBase item) { User anonymousUser = Context.Domain.GetAnonymousUser(); return item.InnerItem.Security.CanRead(anonymousUser); } private void DisableCdn(MediaUrlOptions options) { options.MediaLinkServerUrl = null; } } }
The custom media provider is really simple. It overwrites the GetMediaUrl method and checks to see if the MediaUrlOptions specifies that a CDN should be used. If this is the case it will then check to see if the anonymous user of the domain has read access to the item. If the user does not have access this will indicate that the media is protected in some way and therefore should not be served through the CDN in which case we simply clear the MediaLinkServerUrl property of the MediaUrlOptions object to effectively disable the CDN support before we call the GetMediaUrl method of the base Sitecore MediaProvider to generate the url.
Noew we just need to replace the standard MediaProvider with our own in the Sitecore configuration.
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:x="http://www.sitecore.net/xmlconfig/"> <sitecore> <mediaLibrary> <mediaProvider> <patch:attribute name="type">TGC.Feature.Media.MediaProvider, WDH.Feature.Media</patch:attribute> </mediaProvider> </mediaLibrary> </sitecore> </configuration>
That is all it takes.