Serving Secure Assets with Rails and Nginx

nginx rails secure assets sendfile

11|18|2009

Scenario: Grant access to some assets only to premium users

How do we go about doing this in an efficient way?

Prevent direct access to your assets

If you're using NginX, the following configuration would handle this part:

location /secured_assets {
  internal;
}

So if you have a file named top-secret.pdf in public/secured_assets/top-secret.pdf, then trying to access it directly would result in a 404 not found error.

Create an entry point to your asset

The most obvious way of going about this is to create a route to some controller where you would do the authorization and determine whether the current user trying to retrieve the resource is indeed allowed to access it. Best explained by code.

# in your routes
map.secured_asset '/secured/asset/*slug', :controller => 'secured/assets', :action => 'show'

# in your controller
  def show
    if authorized? # of course do your crazy business logic here
      headers['X-Accel-Redirect'] = File.join("secured_assets", *params[:slug])
      render :nothing => true
    else
      render :nothing => true, :status => 403
    end
  end

The headers part makes sure that nginx is the one responsible for actually streaming the file, freeing your rails application from delivering it.

blog comments powered by Disqus