使用 Flash 消息功能构建机架中间件响应 [英] Building Rack Middleware responses with Flash message functionality

查看:41
本文介绍了使用 Flash 消息功能构建机架中间件响应的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 Sinatra 应用程序,它安装在 /admin 下的 Rails 应用程序上.Sinatra 应用是一个管理仪表板,因此应仅对授权用户开放.

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.

为了加强这一点,我构建了一个机架中间件,它将在调用 Sinatra 应用程序之前运行.

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

逻辑很简单-

  1. 如果用户已通过身份验证,请照常继续
  2. 如果用户未通过身份验证,则使用 Flash 警报消息重定向到根路径(我使用的是 rack-flash gem 允许访问 Rack 中的 flash 消息)
  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)

代码如下.我觉得我在 redirect 方法中遗漏了一些东西.Rack::Builder 块构建了一个 mini-Rack 应用程序,其中的块进一步创建了另一个 Rack 应用程序(Proc),该应用程序使用 flash 消息构建重定向响应.

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.

当我运行它时,我得到 undefined method 'detect' for nil:NilClass,这表明两个块都没有返回有效的非 nil 响应.我需要在这些块之一的某处运行 call 吗?

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?

如果有帮助,我正在使用 Puma 网络服务器.

I'm using a Puma Webserver if that helps.

谢谢!

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

推荐答案

好的,我自己为其他好奇的人解决了这个问题.

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

我不得不使用 env'action_dispatch.request.flash_hash',Flash 中间件 这里

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

我不必使用 rack-flash gem,尽管我确信它在构建 Sinatra 应用程序等时仍然很有用

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

注意: 这是基于 Rails v4.2.4.我相信从那以后对该 Flash 模块进行了几次更改,所以我不知道该键是否已更改.但是你可以通过在最新的 repo 中搜索类似的定义来确认.

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

这篇关于使用 Flash 消息功能构建机架中间件响应的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆