Skip to content

Commit 3152c01

Browse files
committed
Add Authenticated Controllers example to Active Storage guide [skip ci]
The default Active Storage controllers are publicly accessible by default. The generated URLs are hard to guess, but anyone that knows the blob URL will be able to download it. The guides warn about this and advice implementing your own authenticated controllers if required. But currently there is no guidance on how to implement this. This commit adds an example, based on the following comment: rails#38843 (comment) The original warning mentioned 'the URLs being public'. To avoid confusion with the S3 URL, which are only public for 5 minutes, the warning has be changed to 'the controllers being public'. The warning has also been moved up, to make it clear it applies to all redirect and proxy URLs.
1 parent 68a6952 commit 3152c01

File tree

1 file changed

+44
-10
lines changed

1 file changed

+44
-10
lines changed

guides/source/active_storage_overview.md

Lines changed: 44 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -537,6 +537,11 @@ Serving Files
537537

538538
Active Storage supports two ways to serve files: redirecting and proxying.
539539

540+
WARNING: All Active Storage controllers are publicly accessible by default. The
541+
generated URLs are hard to guess, but permanent by design. If your files
542+
require a higher level of protection consider implementing
543+
[Authenticated Controllers](active_storage_overview.html#authenticated-controllers).
544+
540545
### Redirect mode
541546

542547
To generate a permanent URL for a blob, you can pass the blob to the
@@ -555,14 +560,6 @@ indirection decouples the service URL from the actual one, and allows, for
555560
example, mirroring attachments in different services for high-availability. The
556561
redirection has an HTTP expiration of 5 minutes.
557562

558-
WARNING: The URLs generated by Active Storage are hard to guess, but publicly
559-
accessible by default. Anyone that knows the blob URL will be able to download it,
560-
even if a `before_action` in your `ApplicationController` would otherwise
561-
require a login. If your files require a higher level of protection consider
562-
implementing your own authenticated
563-
[`ActiveStorage::Blobs::RedirectController`](ActiveStorage::Blobs::RedirectController) and
564-
[`ActiveStorage::Representations::RedirectController`](ActiveStorage::Representations::RedirectController)
565-
566563
To create a download link, use the `rails_blob_{path|url}` helper. Using this
567564
helper allows you to set the disposition.
568565

@@ -583,8 +580,6 @@ Rails.application.routes.url_helpers.rails_blob_path(user.avatar, only_path: tru
583580

584581
[ActionView::RoutingUrlFor#url_for]: https://api.rubyonrails.org/classes/ActionView/RoutingUrlFor.html#method-i-url_for
585582
[ActiveStorage::Blob#signed_id]: https://api.rubyonrails.org/classes/ActiveStorage/Blob.html#method-i-signed_id
586-
[ActiveStorage::Blobs::RedirectController]: (https://github.com/rails/rails/blob/main/activestorage/app/controllers/active_storage/blobs/redirect_controller.rb)
587-
[ActiveStorage::Representations::RedirectController]: (https://github.com/rails/rails/blob/main/activestorage/app/controllers/active_storage/representations/redirect_controller.rb)
588583

589584
### Proxy mode
590585

@@ -641,6 +636,45 @@ and then generate routes like this:
641636
<%= cdn_image_url(user.avatar.variant(resize_to_limit: [128, 128])) %>
642637
```
643638

639+
### Authenticated Controllers
640+
641+
All Active Storage controllers are publicly accessible by default. The generated
642+
URLs use a plain [`signed_id`][ActiveStorage::Blob#signed_id], making them hard to
643+
guess but permanent. Anyone that knows the blob URL will be able to access it,
644+
even if a `before_action` in your `ApplicationController` would otherwise
645+
require a login. If your files require a higher level of protection, you can
646+
implement your own authenticated controllers, based on the
647+
[`ActiveStorage::Blobs::RedirectController`](ActiveStorage::Blobs::RedirectController) and
648+
[`ActiveStorage::Representations::RedirectController`](ActiveStorage::Representations::RedirectController)
649+
650+
To only allow an account to access their own logo you could do the following:
651+
652+
```ruby
653+
# config/routes.rb
654+
resource :account do
655+
resource :logo
656+
end
657+
```
658+
659+
```ruby
660+
# app/controllers/logos_controller.rb
661+
class LogosController < ApplicationController
662+
# Through ApplicationController:
663+
# include Authenticate, SetCurrentAccount
664+
665+
def show
666+
redirect_to Current.account.logo.url
667+
end
668+
end
669+
```
670+
671+
```erb
672+
<%= image_tag account_logo_path %>
673+
```
674+
675+
[ActiveStorage::Blobs::RedirectController]: (https://github.com/rails/rails/blob/main/activestorage/app/controllers/active_storage/blobs/redirect_controller.rb)
676+
[ActiveStorage::Representations::RedirectController]: (https://github.com/rails/rails/blob/main/activestorage/app/controllers/active_storage/representations/redirect_controller.rb)
677+
644678
Downloading Files
645679
-----------------
646680

0 commit comments

Comments
 (0)