我在我的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
这样的选项,我可以在其中为某些操作应用过滤器。
你如何以干净的方式处理这种情况?
答案 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