Skip to content

Example: Authentication

Mark Evans edited this page Apr 29, 2015 · 1 revision

the user checking logick requires Devise / Warden

basic config:

class Media < ActiveRecord::Base
  belongs_to :user

  dragonfly_accessor :file, app: :private
end


Dragonfly.app(:private).configure do
  secret "..."

  url_format "/private/:job/:sha/:name"

  # prevent users from getting cached responses without authentication.
  # warning: this will cause processing to occur every time the file is requested
  response_header 'Cache-Control', 'private'

  datastore :file,
            root_path: Rails.root.join('private/dragonfly', Rails.env),
            server_root: nil # disable remote urls
end

if only downloading with no processing is required one of the following snippets can be used

Dragonfly.app(:private).configure do
  define_url do |app, job, opts|
    if job.step_types == [:fetch]
      "/download/#{job.uid}"
    else
      app.server.url_for(job, opts)
    end
  end
end

MyApp::Application.routes.draw do
  get "/download/*uid", format: false, to: Dragonfly.app(:private).endpoint { |params, app, env|
    user = env['warden'].user :user
    file = Media.where(file_uid: params[:uid]).first
    if file and user and file.user_id == user.id
      app.fetch params[:uid]
    end
  }
end
MyApp::Application.routes.draw do
  get "/private/:job/:sha/*name", to: Dragonfly.app(:private).endpoint { |params, app, env|
    job = Dragonfly::Job.deserialize params[:job], app
    app.server.instance_eval { validate_job! job }
    job.validate_sha!(params[:sha]) if app.server.verify_urls

    if job.fetch_step
      user = env['warden'].user :user
      file = Media.where(file_uid: job.fetch_step.uid).first
      if file and user and file.user_id == user.id
        app.fetch job.fetch_step.uid
      end
    end
  }
end

to allow complete jobs job can be returned instead of app.fetch uid. but then using the before_serve block instead of a custom route is probaby a better.

Dragonfly.app(:private).configure do
  before_serve do |job, env|
    user = env['warden'].user :user # get devise user from scope 'user'
    throw :halt, [401, {"Content-Type" => "text/plain"}, ["Unauthorized"]] unless user
    # throw :halt, [400, {"Content-Type" => "text/plain"}, ["Bad Request"]] if job.step_types != [:fetch] # only allow download

    # get Media Object the uid belongs to to check authorization.
    # warning: if processors are present which allow multiple fetches authorization is performed only for one of them
    if job.fetch_step
      file = Media.where(file_uid: job.fetch_step.uid).first
      if file
        if file.user_id == user.id
          # allow if user_id matches
        else
          throw :halt, [403, {"Content-Type" => "text/plain"}, ["Forbidden"]]
        end
      else
        # explicitly 404 here to avoid sending files which are no longer in the database but still exist on disk
        throw :halt, [404, {"Content-Type" => "text/plain"}, ["Not Found"]]
      end
    else
      # allow fetch_file, fetch_url and generate
    end
  end
end

Rails.application.middleware.use Dragonfly::Middleware, :private
Clone this wiki locally