2010-09-22 11 views
9

Estoy intentando encontrar la mejor manera de asegurar las URL de clips, pero solo para páginas seguras. Por ejemplo, la página de inicio, que muestra imágenes almacenadas en S3, es http://mydomain.com y la url de la imagen es http://s3.amazonaws.com/mydomainphotos/89/thisimage.JPG?1284314856.URL de clips de seguridad seguras solo para páginas seguras

Tengo páginas seguras como https://mydomain.com/users/my_stuff/49 que tienen imágenes almacenadas en S3, pero el protocolo S3 es http y no https, por lo que el usuario recibe una advertencia del navegador diciendo que algunos elementos de la página no son seguros, bla, bla, bla .

Sé que puedo especificar: s3_protocol en el modelo, pero esto hace que todo sea seguro incluso cuando no es necesario. Por lo tanto, estoy buscando la mejor manera de cambiar el protocolo a https sobre la marcha, solo para páginas seguras.

Uno (probablemente mal) camino sería la creación de un nuevo método de URL como:

def custom_url(style = default_style, ssl = false) 
    ssl ? self.url(style).gsub('http', 'https') : self.url(style) 
end 

Una cosa a tener en cuenta es que estoy usando el plugin ssl_requirement, por lo que podría ser una manera de atarla adentro con eso.

Estoy seguro de que hay una manera simple y estándar de hacer esto que estoy pasando por alto, pero parece que no puedo encontrarlo.

+0

Hola Shagymoe. ..Estoy muy interesado en saber cuál fue tu solución final :) – zetarun

+0

Clipclip github problema aquí: https://github.com/thoughtbot/paperclip/issues/387 – swrobel

Respuesta

7

Si usa Rails 2.3.xo posterior, puede usar el middleware de Rails para filtrar la respuesta antes de enviarla de vuelta al usuario. De esta forma, puede detectar si la solicitud actual es una solicitud HTTPS y modificar las llamadas a s3.amazonaws.com en consecuencia.

Cree un nuevo archivo llamado paperclip_s3_url_rewriter.rb y colóquelo dentro de un directorio que se carga cuando se inicia el servidor. El directorio lib funcionará, pero muchos prefieren crear un directorio app/middleware y agregarlo a la ruta de carga de la aplicación Rails.

Añadir la siguiente clase en el nuevo archivo:

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 

A continuación, sólo registrar el nuevo middleware:

Rails 2.3.x: Agregue la línea siguiente para environment.rb en el comienzo de la Rails::Initializer.run bloquear.
Rails 3.x: Agregue la línea siguiente a application.rb al principio de la clase Application.

config.middleware.use "PaperclipS3UrlRewriter" 

ACTUALIZACIÓN:
que acaba de editar mi respuesta y añadió un cheque por response.is_a?(ActionController::Response) en la sentencia if. En algunos casos (tal vez relacionado con el almacenamiento en caché) el objeto de respuesta es una matriz vacía (?) Y, por lo tanto, falla cuando se invoca request.

ACTUALIZACIÓN 2: que editó el ejemplo de código Rack/Middleware anterior para actualizar también la cabecera Content-Length. De lo contrario, el cuerpo HTML será truncado por la mayoría de los navegadores.

+3

Parece desafortunado para inyectar un S3 url-rewriter en cada solicitud única que su aplicación sirve en lugar de encapsular la lógica para g enerate las URL adecuadas en primer lugar. – Winfield

+0

De hecho, @Winfield, evaluando una expresión regular desatada en cada cuerpo de respuesta está al revés. Use una solución que genere las URL correctas en primer lugar. – Mars

1

pega el siguiente código en una clase controlador:

# 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? 

Por supuesto, puede terminar con esto muy bien en un método.

14

Si alguien se tropieza con esto ahora: ¡Hay un solution in Paperclip desde April 2012! Basta con escribir:

Paperclip::Attachment.default_options[:s3_protocol] = "" 

en un inicializador o utilice la opción s3_protocol dentro de su modelo.

Gracias a @Thomas Watson por iniciar esto.

+0

Esta es la forma oficial de hacer URLs sin esquema ahora. – Karew

+1

Asegúrese de estar utilizando la versión 3.1.4 o superior. Las versiones anteriores tienen un error que incluye el protocolo dos puntos, que romperá todos sus enlaces de imagen. Además, asegúrese de reiniciar su servidor cuando actualice las versiones. – vansan

+0

Véase también http://www.rubydoc.info/github/thoughtbot/paperclip/Paperclip/Storage/S3 –

0

FYI - algunas de las respuestas anteriores no funcionan con Rails 3+, porque ActionController :: Response ha quedado en desuso. Utilice la siguiente:

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 

final

y asegúrese de que se agrega el middleware en un buen lugar en la pila (he añadido después del estante :: Runtime)

config.middleware.insert_after Rack::Runtime, "PaperclipS3UrlRewriter" 
Cuestiones relacionadas