ActiveStorageでアップロードしたファイルに認証をかける
こんにちは。そしてはじめまして。srockstyleといいます。
僕は普段はフリーランスとして活動しておりBPSさんの社員ではありません。ある日普段から仲良くさせていただいていているhachi8833さんに「よかったら記事書いてみない?」とお誘いをいただき、TechRachoのライターとして記事を書かせていただけることになりました。
よろしくお願いします。
はじめに
最近関わっていたプロジェクトでActiveStorageを使う案件があったのですが、ふと以下のことに気づきました。
ActiveStorage、メインファイルとプレビューファイルで参照するControllerが違う上に、両方とも「 Note: These URLs are publicly accessible〜」ってあって、「publicにしたくないなら認証は自分で実装しな」って書いてあって、そこで突き放すんかーいってちょっと思った。
— すろっくさん (@srockstyle) July 24, 2020
ActiveStorageは基本ファイルに対する認証はサポートしてません。もしアップロードしたファイル、またはプレビューするために生成した画像ファイルをログインしたユーザだけに見せたいなどという場合は、自前で認証を実装することになります。
ファイル本体に認証をかける
こちらのファイルを編集します。
このファイルを編集するには、apps/controllers配下に直接ファイルを配置し、元のクラスを上書きする必要があります。そのためapp/controllers配下にActiveStorageのディレクトリを作成します。
$ mkdir [project_name]/app/controllers/active_storage/
作成したディレクトリの下にblobs_controller.rbを作成、編集していきます。
[project_name]/app/controllers/active_storage/blobs_controller.rb
class ActiveStorage::BlobsController < ActiveStorage::BaseController
include ActiveStorage::SetBlob
def show
## 認証してなかったら403
unless authenticate_for_files
head :forbidden
return
end
expires_in ActiveStorage.service_urls_expire_in
redirect_to @blob.service_url(disposition: params[:disposition])
end
private
def authenticate_for_files
## 認証処理
end
end
プレビューするファイルに認証をかける。
ActiveStorageにはPDFや動画などのファイルをアップロードしたときに、そのプレビューを画像として表示する機能があります。
プレビュー画像にも認証をかけたい場合は以下のファイルを使います。
[project_name]/app/controllers/active_storage/representations_controller.rbを作成し、編集していきます。
class ActiveStorage::RepresentationsController < ActiveStorage::BaseController
include ActiveStorage::SetBlob
def show
## 認証してなかったら403
unless authenticate_for_files
head :forbidden
return
end
expires_in ActiveStorage.service_urls_expire_in
redirect_to @blob.representation(params[:variation_key]).processed.service_url(disposition: params[:disposition])
end
private
def authenticate_for_files
## 認証処理
end
end
ActiveStorage::BaseControllerにメソッドを書く
同じロジックなのであればActiveStorage::BaseControllerに認証のメソッドを書くのも選択肢のひとつです。
ファイルを作成、メソッドを追加します。
[project_name]/app/controllers/active_storage/base_controller.rb
class ActiveStorage::BaseController < ActionController::Base
include ActiveStorage::SetCurrent
protect_from_forgery with: :exception
def authenticate_for_files
## 認証処理
end
end
他の二つからはbefore_actionで呼び出します。
[project_name]/app/controllers/active_storage/blobs_controller.rb
class ActiveStorage::BlobsController < ActiveStorage::BaseController
before_action :authenticate_for_files
include ActiveStorage::SetBlob
### 中略
end
[project_name]/app/controllers/active_storage/representations_controller.rb
class ActiveStorage::RepresentationsController < ActiveStorage::BaseController
before_action :authenticate_for_files
include ActiveStorage::SetBlob
### 中略
end
ただ、base_controllerを上書きしてしまうと触る必要のないActiveStorageの処理にも影響がでるので、冗長になってしまいますが、認証をかけたいControllerだけファイルを作成、それぞれに認証のメソッドを書くのがおすすめです。
終わりに
重要なファイルを扱うWebサービスを作っていると、見せたくない画像ファイルやドキュメントなどは期限つきURLだけでは心許ない場合などもやはりあるかと思います。期限つきでかつ認証がかかっているファイルであれば安心して扱っていけるかと思います。
この記事が役にたてば幸いです。