简体   繁体   English

使用设计保护主动存储

[英]Secure active storage with devise

Using devise gem to authenticate all users of an application.使用 devise gem 对应用程序的所有用户进行身份验证。 I'm trying to implement Active Storage.我正在尝试实施 Active Storage。

Let's say that all users must be authenticated as soon as they reach the app:假设所有用户在访问应用程序时都必须进行身份验证:

class ApplicationController < ActionController::Base
  before_action :authenticate_user!

...
end

How to secure the Active Storage generated routes?如何保护 Active Storage 生成的路由?

URL of an uploaded file can be accessed without having to authenticate first.无需先进行身份验证即可访问上传文件的 URL。 The unauthenticated user can get the file url generated by Active Storage.未经身份验证的用户可以获取 Active Storage 生成的文件 url。

This is not a full answer but a starting point:这不是一个完整的答案,而是一个起点:

The gist: You would need to override the redirect controller.要点:您需要覆盖重定向控制器。

The docs for activestorage/app/controllers/active_storage/blobs_controller.rb say: activestorage/app/controllers/active_storage/blobs_controller.rb 的文档说:

If you need to enforce access protection beyond the security-through-obscurity factor of the signed blob references, you'll need to implement your own authenticated redirection controller.如果您需要在签名 blob 引用的隐匿性安全因素之外强制执行访问保护,则需要实现自己的经过身份验证的重定向控制器。

Also if you plan to use previews the docs for activestorage/app/models/active_storage/blob/representable.rb say此外,如果您打算使用预览文档 activestorage/app/models/active_storage/blob/representable.rb

Active Storage provides one [controller action for previews], but you may want to create your own (for example, if you need authentication). Active Storage 提供了一种 [用于预览的控制器操作],但您可能希望创建自己的(例如,如果您需要身份验证)。

Also you might find some relevant information in this rails github issue你也可以在这个 rails github issue 中找到一些相关信息

Update: Here is a minimal example that "should" work for preventing unauthorised access to the redirects when using the devise gem.更新:这是一个“应该”用于在使用devise gem 时防止未经授权访问重定向的最小示例。

How the url, that the user will be redirected to if logged, is then secured is still another story I guess.如果登录后用户将被重定向到的 url 是如何保护的,我猜仍然是另一个故事。 By default they expire after 5 minutes but this could be set to a shorter period like 10 seconds (if you replace line 6 in example below with expires_in 10.seconds )默认情况下,它们会在 5 分钟后过期,但这可以设置为更短的时间,例如 10 秒(如果您将下面示例中的第 6 行替换为expires_in 10.seconds

Create a file app/controllers/active_storage/blobs_controller.rb with the following code:使用以下代码创建文件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

Please note that the only thing that changed from the original code is that the second line is added请注意,与原始代码相比,唯一更改的是添加了第二行

before_action :authenticate_user!

Update 2:更新 2:

Here is a concern that you can include in ActiveStorage::RepresentationsController and ActiveStorage::BlobsController to enable devise authentication for ActiveStorage这是您可以在ActiveStorage::RepresentationsControllerActiveStorage::BlobsController包含的一个问题,以启用ActiveStorage devise身份验证

See gist is at https://gist.github.com/dommmel/4e41b204b97238e9aaf35939ae8e1666 also included here:见要点在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

If you want to implement authentication for all endpoints provided by active storage, you can override the ActiveStorage::BaseController based on the 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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM