在 routes.rb 中获取 Current.user 的可接受方法

An accepted way to get Current.user in routes.rb

提问人:iconoclast 提问时间:8/18/2023 更新时间:11/7/2023 访问量:85

问:

我在 Rails 应用程序中有许多 Rails 引擎,每个引擎目前都有自己的约束类来确定是否允许用户

mount Flipper::UI.app(Flipper) => '/admin/flipper', :as => "feature_flags", constraints: CanAccessFeaturesUI

由于是在 ApplicationController 中设置的,因此在 中尚不可用。有没有任何公认的方法可以将其提供给路由器,以便我可以简单地执行大致如下操作:Current.userroutes.rb

  mount Flipper::UI.app(Flipper) => '/admin/flipper', :as => "feature_flags", constraints: -> do
    Current&.user&.superuser?
  end
Ruby-on-Rails 红宝石 路线

评论

1赞 spickermann 8/18/2023
你有没有考虑过在你的应用程序中添加一个自定义中间件,在 Rails 评估路由之前设置?Current.user
0赞 iconoclast 8/18/2023
@spickermann:是的,这似乎是最好的选择!

答:

4赞 Alex 8/18/2023 #1

详细信息将取决于您用于身份验证的内容。对于 ,一种方法是不使用 :deviseCurrent

# config/routes.rb

constraints ->(req) { req.env["warden"].user&.superuser? } do
  # TODO: secret routes
end

但是内置了此功能:devise

authenticate :user, ->(user) { user.superuser? } do
  # TODO: secret routes
end

https://www.rubydoc.info/gems/devise/4.9.2/ActionDispatch/Routing/Mapper#authenticate-instance_method


要使用,您需要在中间件中设置它。因为它在路由之前运行:Current

$ bin/rails middleware
...
use Rack::ETag
use Rack::TempfileReaper
use Warden::Manager
# this is the place, after warden to use env["warden"]
#                   and before v
run Stackoverflow::Application.routes
# config/initializers/current_middleware.rb

class CurrentMiddleware
  def initialize app
    @app = app
  end

  def call env
    Current.user = env["warden"].user
    @app.call(env)
  end
end

Rails.application.config.middleware.insert_after Warden::Manager, CurrentMiddleware
constraints -> { Current.user&.superuser? } do
  # TODO: secret routes
end