Tech Racho エンジニアの「?」を「!」に。
  • Ruby / Rails関連

ActiveStorageでアップロードしたファイルとプレビュー画像に認証をかける

ActiveStorageでアップロードしたファイルに認証をかける

こんにちは。そしてはじめまして。srockstyleといいます。

僕は普段はフリーランスとして活動しておりBPSさんの社員ではありません。ある日普段から仲良くさせていただいていているhachi8833さんに「よかったら記事書いてみない?」とお誘いをいただき、TechRachoのライターとして記事を書かせていただけることになりました。

よろしくお願いします。

はじめに

最近関わっていたプロジェクトでActiveStorageを使う案件があったのですが、ふと以下のことに気づきました。

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だけでは心許ない場合などもやはりあるかと思います。期限つきでかつ認証がかかっているファイルであれば安心して扱っていけるかと思います。
この記事が役にたてば幸いです。


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。