在使用 Shrine 和 Rails 加密之前为图像文件设置 mime 类型
Posted
技术标签:
【中文标题】在使用 Shrine 和 Rails 加密之前为图像文件设置 mime 类型【英文标题】:setting mime type for image files before they are encrypted with Shrine and Rails 【发布时间】:2021-03-16 01:28:30 【问题描述】:我的应用会加密并上传某些文件,然后让管理员可以看到它们。为了实现后一种功能,my encryption gem's documentation 建议使用如下所示的控制器操作:
def show
user = User.find(params[:id])
lockbox = Lockbox.new(key: Lockbox.attribute_key(table: "id_docs", attribute: "image"))
send_data lockbox.decrypt(user.id_docs.image.read), type: user.id_docs.image.mime_type, disposition: 'inline'
end
我希望文件流式传输,但浏览器不知道如何解释它,而是下载。发生这种情况,文件在上传前已加密,Shrine 将这些文件的 mime 类型设置为 application/octet-stream
。
我的创建操作如下所示:
def create
image = params.require(:id_doc).fetch(:image)
respond_to do |format|
if Shrine.mime_type(image) == 'image/jpeg'
lockbox = Lockbox.new(key: Lockbox.attribute_key(table: "id_docs", attribute: "image"))
encrypted_image = lockbox.encrypt_io(image)
@id_doc = IdDoc.create(user_id: current_user.id, image: encrypted_image)
@id_doc.save
format.html redirect_to root_path
else
format.html redirect_to current_path
end
end
end
如果我不加密文件,mime 类型将保存为image/png
或image/jpeg
,这正是我想要的。
IdDoc.rb 有一个名为 :image
的虚拟属性,它映射到数据库中的 image_data
字段:
class IdDoc < ApplicationRecord
belongs_to :user
validates_presence_of :image
include IdDocUploader::Attachment(:image)
end
schema.rb
create_table "id_docs", force: :cascade do |t|
t.bigint "user_id"
t.text "image_data"
end
保存到image_data
的数据保存为json格式:\"id\":\"iddoc/1/image/2de32e77f306f0e95aed24623e930683.png\",\"storage\":\"store\",\"metadata\":\"filename\":\"Screen Shot 2020-10-31 at 7.24.08 AM.png\",\"size\":47364,\"mime_type\":\"application/octet-stream\"
如何在文件创建之前更改mime_type
的值?有什么办法可以用 Shrine 做到这一点,还是我应该去超级 hacky 并直接解析那个 json?
【问题讨论】:
在将文件返回到浏览器时,您是否查看过我的类型?您可能会发现这是导致下载的原因。 @jad 我如何检查这个?我找到了这个alexkras.com/…,但我很困惑,因为我在执行此操作时不进行 API 调用type: user.id_docs.image.mime_type
...你检查过类型是什么吗?
"Application/octet-stream" 是二进制格式。如果您需要图像,则需要返回与数据匹配的图像 mime-type ... 例如“image/jpeg”
您可以尝试使用类似:flylib.com/books/en/2.44.1/… 并强制文件格式为 jpeg
【参考方案1】:
简单地说:我认为你没有完全按照 Shrine 的意图这样做,有多种方法可以解决这个问题。我会从最好到最差(在我看来,基于复杂性/适当性)对它们进行排名:
加密可以/应该被视为 Shrine 处理/衍生概念的一部分。因此,您希望在那里执行处理并相应地设置元数据。 Shrine 作者本人在此处的线程中概述了处理原始文件的解决方案:https://discourse.shrinerb.com/t/keep-original-file-after-processing/50。 您可以手动覆盖元数据:https://shrinerb.com/docs/metadata#controlling-extraction。这可能意味着不使用基于属性的赋值,而是直接调用附加程序(见下文)。 您可以定义自己的 MIME 类型确定逻辑,如下所述:https://shrinerb.com/docs/plugins/determine_mime_type。 您已经在使用Shrine.mime_type
。使用您从中获得的值并将其存储在 id_docs
模型上的单独数据库列 mime_type
中,然后在您从数据库中读取时使用它。请注意,这可能暗示此列中的值与您从文件元数据的 mime 类型中获得的值不同步。
直接使用attacher:
mime_type = Shrine.mime_type(image)
# ...
@id_doc = IdDoc.create(user_id: current_user.id) do |id_doc|
id_doc.image_attacher.model_assign(encrypted_image, metadata: mime_type: mime_type )
end
【讨论】:
以上是关于在使用 Shrine 和 Rails 加密之前为图像文件设置 mime 类型的主要内容,如果未能解决你的问题,请参考以下文章
Rails 5 + Shrine + 多态模型 + 漂亮的位置
Rails 6 - Shrine - ImageProcessing - 获取原始上传文件
Shrine Gem Ruby on Rails 无服务器图像处理程序,后台作业
从 ActiveStorage 迁移到 Shrine 的 Rake 任务