Rails应用自动为上传PDF、图片加密码并存至AWS S3的技术咨询
解决方案
一、为用户上传的PDF添加密码保护
你已经用Prawn实现了系统生成PDF的加密,但Prawn更适合创建新PDF,处理已上传的现有PDF,推荐使用纯Ruby实现的HexaPDF库(无需依赖外部工具),具体步骤如下:
- 把HexaPDF加入Gemfile:
gem 'hexapdf'
执行bundle install完成安装。
- 编写加密逻辑(可放在上传处理的Controller或Service类中):
# uploaded_file为用户上传的PDF文件对象,user为当前用户实例 def encrypt_uploaded_pdf(uploaded_file, user) # 基于用户数据生成密码,示例:用户ID+8位随机字符串 password = "#{user.id}_#{SecureRandom.hex(8)}" # 加载上传的PDF文件 doc = HexaPDF::Document.open(uploaded_file.path) # 设置密码保护:user_password是打开密码,owner_password用于修改权限 doc.security.set_password(user_password: password, owner_password: SecureRandom.hex(16)) # 生成加密后的临时文件 encrypted_pdf_path = "#{Dir.tmpdir}/encrypted_#{SecureRandom.uuid}.pdf" doc.write(encrypted_pdf_path) # 上传加密后的文件到AWS S3(复用你已有的S3上传逻辑) s3_object = Aws::S3::Object.new(bucket_name: '你的存储桶名称', key: "protected_pdfs/#{user.id}/#{SecureRandom.uuid}.pdf") s3_object.upload_file(encrypted_pdf_path) # 将密码存入数据库,方便后续提供给用户 user.update!(pdf_password: password) # 清理临时文件 File.delete(encrypted_pdf_path) if File.exist?(encrypted_pdf_path) s3_object.public_url # 返回加密文件的S3访问地址 end
如果偏好使用外部工具pdftk,也可以通过系统命令调用(需服务器预先安装pdftk),示例代码:
def encrypt_with_pdftk(uploaded_file, user) password = "#{user.id}_#{SecureRandom.hex(8)}" output_path = "#{Dir.tmpdir}/encrypted_pdf.pdf" # 执行pdftk加密命令 system("pdftk #{uploaded_file.path} output #{output_path} user_pw #{password}") # 后续上传S3、保存密码逻辑同上 end
二、图片文件的密码保护方案
绝大多数图片格式(JPG、PNG、GIF等)不支持原生密码保护,可行方案是先将图片转换为PDF,再为PDF添加密码保护,具体步骤:
- 加入图片处理库
mini_magick到Gemfile:
gem 'mini_magick'
执行bundle install完成安装。
- 图片转PDF并加密的示例代码:
def protect_image_with_password(uploaded_image, user) # 生成密码 password = "#{user.id}_#{SecureRandom.hex(8)}" # 用MiniMagick将图片转换为PDF pdf_path = "#{Dir.tmpdir}/image_to_pdf_#{SecureRandom.uuid}.pdf" image = MiniMagick::Image.open(uploaded_image.path) image.format('pdf') image.write(pdf_path) # 复用HexaPDF加密逻辑处理生成的PDF doc = HexaPDF::Document.open(pdf_path) doc.security.set_password(user_password: password, owner_password: SecureRandom.hex(16)) encrypted_pdf_path = "#{Dir.tmpdir}/encrypted_image_pdf_#{SecureRandom.uuid}.pdf" doc.write(encrypted_pdf_path) # 上传到AWS S3 s3_object = Aws::S3::Object.new(bucket_name: '你的存储桶名称', key: "protected_images/#{user.id}/#{SecureRandom.uuid}.pdf") s3_object.upload_file(encrypted_pdf_path) # 保存密码到数据库 user.update!(image_pdf_password: password) # 清理临时文件 File.delete(pdf_path) if File.exist?(pdf_path) File.delete(encrypted_pdf_path) if File.exist?(encrypted_pdf_path) s3_object.public_url end
你也可以直接用Prawn把图片插入新PDF再加密,示例:
def protect_image_with_prawn(uploaded_image, user) password = "#{user.id}_#{SecureRandom.hex(8)}" pdf_path = "#{Dir.tmpdir}/prawn_image_pdf.pdf" Prawn::Document.generate(pdf_path, password: password) do |pdf| pdf.image uploaded_image.path, fit: [500, 700] # 适配PDF页面尺寸 end # 后续上传S3、保存密码逻辑同上 end
内容的提问来源于stack exchange,提问作者user3204760
相关产品推荐
相关产品推荐

