如何处理Grape中特定操作的过滤器之前?

时间:2016-10-17 14:08:16

标签: ruby-on-rails ruby grape grape-api

我在我的Rails项目中安装Grape来构建RESTful API。

现在有些端点需要进行身份验证,而其他端点则不需要身份验证。

例如,我的users终点看起来像是:

module Backend
  module V1
    class Users < Grape::API
      include Backend::V1::Defaults

      before { authenticate! }

      resource :users do

        desc "Return a user"
        params do
          requires :id, type: Integer, desc: 'User id'
        end
        get ':id' do
          UsersService::Fetch.new(current_user,params).call
        end

        desc "Update a user"
        params do
          requires :id, type: Integer, desc: 'User id'
          requires :display_name, type: String, desc: 'Display name'
          requires :email, type: String, desc: 'Email'
        end
        post ':id' do
          UsersService::Save.new(current_user,params).call
        end

        desc "Reset user password"
        params do
          requires :old_password, type: String, desc: 'old password'
          requires :password, type: String, desc: 'new password'
        end
        post 'password/reset' do
          PasswordService::Reset.new(current_user,params).call
        end

        desc "Forget password"
        params do
          requires :email, type: String
        end
        post 'password/forget' do
          PasswordService::Forget.new(current_user,params).call
        end            

      end
    end
  end
end

现在您可以看到,除password/forget之外的所有操作都需要用户登录/验证。创建一个新的终点也是没有意义的,让我们说passwords只是删除password/forget,从逻辑上讲,这个终点应该与用户资源相关。

问题在于Grape before过滤器没有像except, only这样的选项,我可以在其中为某些操作应用过滤器。

你如何以干净的方式处理这种情况?

3 个答案:

答案 0 :(得分:5)

我能想到的一种方法是使用route_setting为您想要绕过auth的路由添加自定义属性。在调用authenticate!之前,在过滤器中检查这些属性。像下面这样的东西应该有效:

module Backend
  module V1
    class Users < Grape::API
      include Backend::V1::Defaults

      before { authenticate! unless route.settings[:auth] && route.settings[:auth][:disabled] }

      resource :users do

        desc "Return a user"
        params do
          requires :id, type: Integer, desc: 'User id'
        end
        get ':id' do
          UsersService::Fetch.new(current_user,params).call
        end

        desc "Update a user"
        params do
          requires :id, type: Integer, desc: 'User id'
          requires :display_name, type: String, desc: 'Display name'
          requires :email, type: String, desc: 'Email'
        end
        post ':id' do
          UsersService::Save.new(current_user,params).call
        end

        desc "Reset user password"
        params do
          requires :old_password, type: String, desc: 'old password'
          requires :password, type: String, desc: 'new password'
        end
        post 'password/reset' do
          PasswordService::Reset.new(current_user,params).call
        end

        desc "Forget password"
        route_setting :auth, disabled: true
        params do
          requires :email, type: String
        end
        post 'password/forget' do
          PasswordService::Forget.new(current_user,params).call
        end            

      end
    end
  end
end

答案 1 :(得分:3)

通过使用namespace来提供帮助的肮脏方式,例如:

module Backend
  module V1
    class Users < Grape::API
      include Backend::V1::Defaults

      namespace :users do
        desc "Forget password"
        params do
          requires :email, type: String
        end
        post 'password/forget' do
          PasswordService::Forget.new(current_user,params).call
        end

        namespace do
          before { authenticate! }

          desc "Return a user"
          params do
            requires :id, type: Integer, desc: 'User id'
          end
          get ':id' do
            UsersService::Fetch.new(current_user,params).call
          end

          desc "Update a user"
          params do
            requires :id, type: Integer, desc: 'User id'
            requires :display_name, type: String, desc: 'Display name'
            requires :email, type: String, desc: 'Email'
          end
          post ':id' do
            UsersService::Save.new(current_user,params).call
          end

          desc "Reset user password"
          params do
            requires :old_password, type: String, desc: 'old password'
            requires :password, type: String, desc: 'new password'
          end
          post 'password/reset' do
            PasswordService::Reset.new(current_user,params).call
          end            

        end
      end
    end
  end
end

这样我们就不会在users/password/forget的过滤器之前运行,但其余的我们将运行before { authenticate! }

答案 2 :(得分:0)

更清晰一点,但也许不是那么明显的方法是将名称空间拆分为单独的子类:

module API
  module Users
    class Root < Grape::API
      namespace :users do
        mount Create # <= `before` callback is not executed

        before do
          authenticate!
        end

        mount Update # <= `before` callback is executed
      end
    end
  end
end

相对目录结构将如下所示:

 api/users/root.rb
 api/users/create.rb
 api/users/update.rb