繁体   English   中英

Rails 6、Devise 和活动存储

[英]Rails 6, Devise and Active Storage

我在 Rails 6 应用程序中使用 Devise 和 Active Storage。 目前正在使用before_action: authenticate_user! 为非用户禁用所有图像,这很好,除了我想让我的record_typeactive_storage_attachments为“新闻”的图像可供用户和非用户查看。

下面的代码是我目前所拥有的,查看记录类型为新闻的record_type ::Attachment。 此代码显示用户和非用户的所有图像,这并不理想。

class ActiveStorage::BaseController < ActionController::Base
  before_action :allow_certain_assets
  include ActiveStorage::SetCurrent

  protect_from_forgery with: :exception
  
  private
  
  def allow_certain_assets
    if (ActiveStorage::Attachment.where(record_type: 'News')).present?
    else
      authenticate_user!
    end
  end
  
end

您的代码的问题是您正在这样做:

(ActiveStorage::Attachment.where(record_type: 'News')).present?

这将检查整个数据库,如果有任何attachmentrecord_type “新闻”。 但是,您需要检查用户尝试访问的特定图像是否属于“新闻”类型,然后允许他或不允许他。 执行此操作的一种方法是您可以检查的显示操作:

def show
  # this code might be incorrect and I am not sure how you would be getting 
  # the attachment object but this would explain a way you can authenticate it
  @attachment = ActiveStorage::Attachment.find params[:id]
  authenticate_user! unless @attachment.record_type == 'News'
end

因此,这将检查用户尝试访问的特定对象。

添加在:

这种类型的授权可以使用一些授权库自动完成,例如:

  1. 罐头罐头
  2. 权威人士

您也可以允许访客用户使用某些类型的图像,而其他类型的图像仅适用于注册用户。

这将与Pundit gem 一起使用(@Deep此处提到的选项之一)

# controller
class ImagesController < ApplicationController
  def index
    authorize :image, :index?
    @images = policy_scope(ActiveRecord::Attachment)
  end

  def show
    @image = policy_scope(ActiveRecord::Attachment).find(params[:id])
    authorize @image, policy_class: ImagePolicy
  end
end
# policy
class ImagePolicy < ApplicationPolicy
  def index?
    true # must be true so that every can see the list
  end

  def show?
    true # optional: add more logic here
  end

  class Scope
    def initialize(user, scope)
      @user  = user
      @scope = scope
    end

    def resolve
      if user
        scope
      else        
        scope.where(record_type: 'News') # we limit the records here
      end
    end
  end
end

这里的其他答案对我的用例很有帮助,但如果其他人难以获得原始记录来做 model 特定的事情(就像我所做的那样),那么find_signed可能有助于获取其他检查、条件等所需的信息。

class ActiveStorage::BaseController < ActionController::Base
  include Rails.application.routes.url_helpers
  include ActiveStorage::SetCurrent
  before_action :check_attachment
  protect_from_forgery with: :exception
  
  private

  def check_attachment
    blob_id = ActiveStorage::Blob.find_signed(params[:signed_id])
    attachment = ActiveStorage::Attachment.find_by(blob_id: blob_id)
    record = attachment.record_type.constantize.find(attachment.record_id)
    if # Other model specific checks
      # Can also redirect somewhere else here if needed:
      # redirect_to root_path, alert: 'You do not have permission to access this.'
    end
  end
end

暂无
暂无

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

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