使用设计保护主动存储 [英] Secure active storage with devise
问题描述
使用 devise gem 对应用程序的所有用户进行身份验证.我正在尝试实施 Active Storage.
Using devise gem to authenticate all users of an application. I'm trying to implement 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
如何保护 Active Storage 生成的路由?
How to secure the Active Storage generated routes?
无需先进行身份验证即可访问上传文件的 URL.未经身份验证的用户可以获取到 Active Storage 生成的文件 url.
URL of an uploaded file can be accessed without having to authenticate first. The unauthenticated user can get the file url generated by Active Storage.
推荐答案
这不是一个完整的答案,而是一个起点:
This is not a full answer but a starting point:
要点:您需要覆盖重定向控制器.
The gist: You would need to override the redirect controller.
activestorage/app/controllers/active_storage/blobs_controller.rb 的 文档说:
The docs for activestorage/app/controllers/active_storage/blobs_controller.rb say:
如果您需要执行超出范围的访问保护已签名 blob 引用的安全性通过隐匿性因素,您需要实现自己的经过身份验证的重定向控制器.
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.
此外,如果您打算使用预览,请查看 文档activestorage/app/models/active_storage/blob/representable.rb 说
Also if you plan to use previews the docs for activestorage/app/models/active_storage/blob/representable.rb say
Active Storage 提供了一种 [用于预览的控制器操作],但您可能希望创建自己的(用于例如,如果您需要身份验证).
Active Storage provides one [controller action for previews], but you may want to create your own (for example, if you need authentication).
更新:这是一个应该"用于在使用 devise
gem 时防止对重定向进行未经授权的访问的最小示例.
Update:
Here is a minimal example that "should" work for preventing unauthorised access to the redirects when using the devise
gem.
如果登录后用户将被重定向到的 url 是如何保护的,我猜仍然是另一个故事.默认情况下,它们会在 5 分钟后过期,但可以将其设置为更短的时间,例如 10 秒(如果您将下面示例中的第 6 行替换为 expires_in 10.seconds
)
How the url, that the user will be redirected to if logged, is then secured is still another story I guess. 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
)
使用以下代码创建文件 app/controllers/active_storage/blobs_controller.rb
:
Create a file app/controllers/active_storage/blobs_controller.rb
with the following code:
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!
更新 2:
这里有一个问题,您可以在 ActiveStorage::RepresentationsController
和 ActiveStorage::BlobsController
中加入,以便为 启用
devise
身份验证活动存储
Here is a concern that you can include in ActiveStorage::RepresentationsController
and ActiveStorage::BlobsController
to enable devise
authentication for ActiveStorage
请参阅要点 https://gist.github.com/dommmel/4e41b204b97238e9aaf359 也包括在这里:
See gist is at https://gist.github.com/dommmel/4e41b204b97238e9aaf35939ae8e1666 also included here:
# 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
这篇关于使用设计保护主动存储的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!