Building Rack Middleware responses with Flash message functionality

房东的猫 提交于 2019-12-13 02:24:46

问题


I have a Sinatra app that's mounted on a Rails app under /admin. The Sinatra app is an admin dashboard, and therefore should only be available to authorized users.

To enforce that, I built a piece of Rack Middleware that will run before the Sinatra app is called.

The logic is simple -

  1. If user is authenticated, continue as normal
  2. If user is not authenticated, redirect to the root path with a flash alert message (I'm using the rack-flash gem to allow access to the flash messages in Rack)

Code below. I feel like I'm missing something in the redirect method. The Rack::Builder block constructs a mini-Rack application and the block inside further creates another Rack application (the Proc) that builds the Redirect Response with flash message.

When I run it, I get undefined method 'detect' for nil:NilClass, which indicates that neither block is returning a valid non-nil response. Do I need to run call somewhere on one of these blocks?

I'm using a Puma Webserver if that helps.

Thanks!

require "rack"
require "rack-flash"

class AdminAuthorizer
  def initialize(app)
    @app = app
  end

  def call(env)
    @env = env

    id = @env["rack.session"][:user_id]
    user = User.where(id: id).first

    # Check if user is authorized, otherwise redirect  
    user.admin? ? ok : redirect
  end

  private

  def ok
    @app.call(@env)
  end

  def redirect
    Rack::Builder.new do
      use Rack::Flash, sweep: true, accessorize: true

      run(
        Proc.new do |env|
          env["x-rack.flash"].alert = "Insufficient permissions"

          res = Rack::Response.new
          res.redirect("/")
          res.finish
        end
      )
    end
  end
end

回答1:


Ok, figured it out myself for anyone else that's curious.

I had to use the env key 'action_dispatch.request.flash_hash', which is used by the Flash middelware here

I didn't have to use the rack-flash gem, although I'm sure that's still useful when building Sinatra apps and such

NOTE: This is on Rails v4.2.4. I believe there have been several changes to that Flash module since, so I don't know if that key has changed. But you can confirm by searching the latest repo for a similar definition.

require "rack"


class AdminAuthorizer
  FLASH = ActionDispatch::Flash

  def initialize(app)
    @app = app
  end

  def call(env)
    @env = env

    id = @env["rack.session"][:user_id]
    user = User.where(id: id).first

    # Check if user is authorized, otherwise redirect
    user.admin? ? ok : redirect
  end

  private

  def ok
    @app.call(@env)
  end

  def redirect
    # Calls a Rack application (the defined Proc). If you want to do more steps
    # or get fancier, you can wrap this in a Rack::Builder call
    #
    # Rack::Builder.app(redirect_proc)
    #   use (blah)
    #   run (blah)
    # end.call(@env)
    #
    redirect_proc.call(@env)
  end

  def redirect_proc
    Proc.new do |env|
      # Use the key 'action_dispatch.request.flash_hash' to set
      # an new FlashHash object. This will overrite any existing FlashHash
      # object, so use it carefully. You can probably avoid that by checking
      # for an existing one and adding to it.
      env[FLASH::KEY] = FLASH::FlashHash.new(alert: "Insufficient permissions")

      # Construct the redirect response
      res = Rack::Response.new
      res.redirect("/")
      res.finish
    end
  end
end


来源:https://stackoverflow.com/questions/32954916/building-rack-middleware-responses-with-flash-message-functionality

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!