I ran into this requirement today and initially assumed a plugin would be required, but then I spotted that the native Assets action menu already included a Download File option and it was working just fine with files that weren’t publicly accessible. Maybe we could use that rather than reinventing the wheel?
If you check DownloadFileElementAction.php you can see the markup and JS that’s used for this button in the control panel. It generates a simple <form>
tag that POSTs to assets/downloadAsset
. With a tiny bit of tweaking that can be converted to a code suitable for use in a frontend template:
<form method="post" target="_blank" action="">
{{ getCsrfInput() }}
<input type="hidden" name="action" value="assets/downloadAsset" />
<input type="hidden" name="assetId" value="123" />
<input type="submit" value="Submit" />
</form>
This works a treat and includes all native permissions checks as you’d expect. So long as the requesting user has the viewAssetSource
permission for the Asset Source the download will work. If the requesting user is logged out then they are automatically redirected to your loginPath
.
The only snag I’ve noticed is that Craft does return a JSON formatted error string if your user doesn’t have permission to view the asset. In my case this doesn’t matter, as all authenticated users will have permission to view the files - we’re just trying to prevent guests from seeing them.
Since this approach requires POSTs it’s a bit limiting (secured img
tags are a non-starter), but for typical download button use cases it looks fine to me and avoids the need for third party plugins.
(This is a Craft 2 build, I haven’t tested this with Craft 3)