2015-10-05 1 views
0

J'ai une application Sinatra montée sur une application Rails sous /admin. L'application Sinatra est un tableau de bord d'administration, et ne devrait donc être disponible que pour les utilisateurs autorisés. Pour renforcer cela, j'ai construit un morceau de Middleware Rack qui fonctionnera avant que l'application Sinatra soit appelée.Réponses de l'intergiciel Rack Building avec fonctionnalité de message Flash

La logique est simple -

  1. Si l'utilisateur est authentifié, continuent normalement
  2. Si l'utilisateur n'est pas authentifié, redirection vers le chemin racine avec un flash message d'alerte (j'utilise la pierre précieuse rack-flash pour permettre l'accès aux messages flash dans Rack)

Code ci-dessous. J'ai l'impression de manquer quelque chose dans la méthode redirect. Le bloc Rack::Builder construit une application mini-Rack et le bloc à l'intérieur crée une autre application Rack (le Proc) qui construit la réponse de redirection avec un message flash.

Lorsque je l'exécute, j'obtiens undefined method 'detect' for nil:NilClass, ce qui indique qu'aucun des deux blocs ne renvoie une réponse non-nil valide. Dois-je exécuter call quelque part sur l'un de ces blocs? J'utilise un serveur Web Puma si cela peut aider.

Merci!

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 

Répondre

1

Ok, je l'ai trouvé moi-même pour quelqu'un d'autre qui est curieux.

je devais utiliser la env'action_dispatch.request.flash_hash' clé, qui est utilisé par le middelware flash here

Je ne devais pas utiliser la pierre précieuse rack-flash, même si je suis sûr que ce encore utile lors de la construction des applications Sinatra et autres

REMARQUE: Rails v4.2.4. Je crois qu'il y a eu plusieurs changements à ce module Flash depuis, donc je ne sais pas si cette clé a changé. Mais vous pouvez confirmer en recherchant le dernier repo pour une définition similaire.

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