我正在尝试找到使回形针网址安全的最佳方法,但仅限于安全网页。
例如,显示存储在S3中的图像的主页为http://mydomain.com,图片网址为http://s3.amazonaws.com/mydomainphotos/89/thisimage.JPG?1284314856。
我有像https://mydomain.com/users/my_stuff/49这样的安全页面,其中的图像存储在S3中,但S3协议是http而不是https,因此用户会从浏览器收到警告,说明页面上的某些元素不安全,等等等等。
我知道我可以在模型中指定:s3_protocol,但这使得一切都安全,即使没有必要。因此,我正在寻找将协议更改为https的最佳方法,仅用于安全页面。
一种(可能是坏的)方法是创建一个新的url方法,如:
def custom_url(style = default_style, ssl = false)
ssl ? self.url(style).gsub('http', 'https') : self.url(style)
end
需要注意的一点是,我正在使用ssl_requirement插件,因此可能有办法将其与之相关联。
我确信有一些简单,标准的方法可以做到这一点,但我似乎无法找到它。
答案 0 :(得分:17)
如果有人现在偶然发现:solution in Paperclip以来April 2012!只需写下:
Paperclip::Attachment.default_options[:s3_protocol] = ""
在初始化程序中或使用模型中的s3_protocol
选项。
感谢@Thomas Watson发起这个。
答案 1 :(得分:7)
如果使用Rails 2.3.x或更高版本,您可以使用Rails中间件过滤响应,然后再将其发送回用户。这样,您可以检测当前请求是否为HTTPS请求,并相应地修改对s3.amazonaws.com的调用。
创建一个名为paperclip_s3_url_rewriter.rb
的新文件,并将其放在服务器启动时加载的目录中。 lib
目标可以使用,但许多人更喜欢创建app/middleware
目录并将其添加到Rails应用程序加载路径。
将以下类添加到新文件中:
class PaperclipS3UrlRewriter
def initialize(app)
@app = app
end
def call(env)
status, headers, response = @app.call(env)
if response.is_a?(ActionController::Response) && response.request.protocol == 'https://' && headers["Content-Type"].include?("text/html")
body = response.body.gsub('http://s3.amazonaws.com', 'https://s3.amazonaws.com')
headers["Content-Length"] = body.length.to_s
[status, headers, body]
else
[status, headers, response]
end
end
end
然后注册新的中间件:
Rails 2.3.x:将以下行添加到Rails::Initializer.run
块开头的environment.rb中。
Rails 3.x:将以下行添加到Application类开头的application.rb中。
config.middleware.use "PaperclipS3UrlRewriter"
<强>更新强>
我刚刚编辑了我的答案,并在if语句中添加了response.is_a?(ActionController::Response)
的检查。在某些情况下(可能与缓存相关),响应对象是一个空数组(?),因此在调用request
时失败。
更新2:
我编辑了上面的机架/中间件代码示例,以便更新Content-Length
标头。否则大多数浏览器都会截断HTML正文。
答案 2 :(得分:1)
在控制器类中使用以下代码:
# locals/arguments/methods you must define or have available:
# attachment - the paperclip attachment object, not the ActiveRecord object
# request - the Rack/ActionController request
AWS::S3::S3Object.url_for \
attachment.path,
attachment.options[:bucket].to_s,
:expires_in => 10.minutes, # only necessary for private buckets
:use_ssl => request.ssl?
你当然可以很好地把它包装成一个方法。
答案 3 :(得分:0)
仅供参考 - 上面的一些答案不适用于Rails 3+,因为ActionController :: Response已被弃用。使用以下内容:
class PaperclipS3UrlRewriter
def initialize(app)
@app = app
end
def call(env)
status, headers, response = @app.call(env)
if response.is_a?(ActionDispatch::BodyProxy) && headers && headers.has_key?("Content-Type") && headers["Content-Type"].include?("text/html")
body_string = response.body[0]
response.body[0] = body_string.gsub('http://s3.amazonaws.com', 'https://s3.amazonaws.com')
headers["Content-Length"] = body_string.length.to_s
[status, headers, response]
else
[status, headers, response]
end
end
端
并确保将中间件添加到堆栈中的好位置(我在Rack :: Runtime之后添加它)
config.middleware.insert_after Rack::Runtime, "PaperclipS3UrlRewriter"