ruby-on-rails 使用设备保护主动存储

jpfvwuh4  于 2023-04-08  发布在  Ruby
关注(0)|答案(3)|浏览(117)

使用devise gem对应用程序的所有用户进行身份验证。我正在尝试实现活动存储。
假设所有用户在访问应用程序时都必须进行身份验证:

class ApplicationController < ActionController::Base
  before_action :authenticate_user!

...
end

如何保护Active Storage生成的路由?
上传文件的URL不需要认证就可以访问,未经认证的用户可以获取Active Storage生成的文件URL。

hgb9j2n6

hgb9j2n61#

这不是一个完整的答案,而是一个起点:
要点:您需要覆盖重定向控制器。
docs for activestorage/app/controllers/active_storage/blobs_controller.rb说道:
如果您需要在签名的blob引用的通过隐藏的安全因素之外实施访问保护,则需要实现自己的身份验证重定向控制器。
另外,如果您计划使用预览文档来预览ActiveStorage/app/models/active_storage/blob/representable.rb,请说
Active Storage提供了一个[用于预览的控制器操作],但您可能希望创建自己的操作(例如,如果您需要身份验证)。
您还可以在this rails github issue中找到一些相关信息

**更新:**这里是一个最小的例子,当使用devise gem时,“应该”可以防止未经授权的访问重定向。

我想,如果用户登录,将被重定向到的URL如何被保护,这仍然是另一个故事。默认情况下,它们在5分钟后过期,但这可以设置为更短的时间,如10秒(如果您将下面示例中的第6行替换为expires_in 10.seconds
使用以下代码创建一个文件app/controllers/active_storage/blobs_controller.rb

class ActiveStorage::BlobsController < ActiveStorage::BaseController
  before_action :authenticate_user!
  include ActiveStorage::SetBlob

  def show
    expires_in ActiveStorage::Blob.service.url_expires_in
    redirect_to @blob.service_url(disposition: params[:disposition])
  end
end

请注意,与original code相比,唯一的变化是添加了第二行

before_action :authenticate_user!

更新二:

以下是您可以在ActiveStorage::RepresentationsControllerActiveStorage::BlobsController中包含的一个问题,以便为ActiveStorage启用devise身份验证
参见要点https://gist.github.com/dommmel/4e41b204b97238e9aaf35939ae8e1666,也包括在此处:

# Rails controller concern to enable Devise authentication for ActiveStorage.
# Put it in +app/controllers/concerns/blob_authenticatable.rb+ and include it when overriding
# +ActiveStorage::BlobsController+ and +ActiveStorage::RepresentationsController+.
# 
# Optional configuration:
# 
# Set the model that includes devise's database_authenticatable.
# Defaults to Devise.default_scope which defaults to the first
# devise role declared in your routes (usually :user)
#
#   blob_authenticatable resource: :admin
#   
# To specify how to determine if the current_user is allowed to access the 
# blob, override the can_access_blob? method
#   
# Minimal example:
# 
#   class ActiveStorage::BlobsController < ActiveStorage::BaseController
#     include ActiveStorage::SetBlob
#     include AdminOrUserAuthenticatable
#     
#     def show
#       expires_in ActiveStorage::Blob.service.url_expires_in
#       redirect_to @blob.service_url(disposition: params[:disposition])
#     end
#   end
# 
# Complete example:
# 
#   class ActiveStorage::RepresentationsController < ActiveStorage::BaseController
#     include ActiveStorage::SetBlob
#     include AdminOrUserAuthenticatable
# 
#     blob_authenticatable resource: :admin
#
#     def show
#       expires_in ActiveStorage::Blob.service.url_expires_in
#       redirect_to @blob.representation(params[:variation_key]).processed.service_url(disposition: params[:disposition])
#     end
#     
#     private
#
#       def can_access_blob?(current_user)
#         @blob.attachments.map(&:record).all? { |record| record.user == current_user }
#       end
#   end

module BlobAuthenticatable
  extend ActiveSupport::Concern

  included do
    around_action :wrap_in_authentication
  end
  
  module ClassMethods
    def auth_resource
      @auth_resource || Devise.default_scope
    end

    private

      def blob_authenticatable(resource:)
        @auth_resource = resource
      end
  end

  private

    def wrap_in_authentication
      is_signed_in_and_authorized = send("#{self.class.auth_resource}_signed_in?") \
        & can_access_blob?(send("current_#{self.class.auth_resource}"))

      if is_signed_in_and_authorized
        yield
      else
        head :unauthorized
      end
    end

    def can_access_blob?(_user)
      true
    end
end
yhived7q

yhived7q2#

如果要对主动存储提供的所有端点实施身份验证,可以基于original implementation覆盖ActiveStorage::BaseController

# app/controllers/active_storage/base_controller.rb

# frozen_string_literal: true

# The base class for all Active Storage controllers.
class ActiveStorage::BaseController < ActionController::Base
  before_action :authenticate_user!
  include ActiveStorage::SetCurrent

  protect_from_forgery with: :exception
end
72qzrwbm

72qzrwbm3#

我对这里的解决方案不满意:重新实现所有控制器和路由,或覆盖ActiveStorage::BaseController
当原始源代码更改时,两者似乎都可能会中断。
我所做的是将身份验证修补到现有的ActiveStorage::BaseController中:

# config/initializers/active_storage.rb
Rails.application.config.after_initialize do
  ActiveStorage::BaseController.class_eval do
    before_action :authenticate_user!
  end
end

我还没有测试所有的活动存储的功能,所以我不能保证它会全部工作,但到目前为止,它的工作,因为我的预期。

相关问题