问题描述
我有一个 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.
逻辑很简单-
- 如果用户已通过身份验证,请照常继续
- 如果用户未通过身份验证,则使用 Flash 警报消息重定向到根路径(我使用的是 rack-flash gem 允许访问 Rack 中的 flash 消息)
- If user is authenticated, continue as normal
- 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 消息功能构建机架中间件响应的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!