如何限制对资源的索引操作的访问,而不是对属于该用户的单个记录的访问?
How do I restrict access to the index action of my resource, but not to the individual record that belongs to that user?
这就是我的 ability.rb
的截断版本:
class Ability
include CanCan::Ability
def initialize(user)
alias_action :create, :read, :update, :destroy, to: :crud
user ||= User.new # guest user (not logged in)
if user.has_role?(:admin)
can :manage, :all
else
cannot :read, User
can :crud, User, id: user.id
# cannot :read, :users unless user.has_role? :admin
end
end
end
我的 UsersController
看起来像这样:
class UsersController < ApplicationController
load_and_authorize_resource
before_action :set_user, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!, except: [:show]
# truncated for brevity
end
所以在这里,我想做的是 User#Index
,我想将其限制为管理员用户。但与此同时,每个用户应该能够访问自己的用户页面。
当我尝试上面的方法时,这对我来说很有意义,我可以访问 /settings
作为 current_user
,但我仍然可以访问 Users#Index
这是我不想。
这是日志的样子:
Started GET "/users/1547" for 127.0.0.1 at 2016-06-26 03:39:57 -0500
DEPRECATION WARNING: before_filter is deprecated and will be removed in Rails 5.1. Use before_action instead. (called from <class:UsersController> at myapp/controllers/users_controller.rb:2)
Processing by UsersController#show as HTML
Parameters: {"id"=>"1547"}
User Load (2.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = LIMIT [["id", 1547], ["LIMIT", 1]]
User Load (1.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = ORDER BY "users"."id" ASC LIMIT [["id", 1547], ["LIMIT", 1]]
Role Load (1.8ms) SELECT "roles".* FROM "roles" INNER JOIN "users_roles" ON "roles"."id" = "users_roles"."role_id" WHERE "users_roles"."user_id" = AND (((roles.name = 'admin') AND (roles.resource_type IS NULL) AND (roles.resource_id IS NULL))) [["user_id", 1547]]
CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = LIMIT [["id", 1547], ["LIMIT", 1]]
Rendering users/show.html.erb within layouts/application
Rendered shared/_navbar.html.erb (2.4ms)
Rendered shared/_footer.html.erb (1.3ms)
Completed 200 OK in 244ms (Views: 196.4ms | ActiveRecord: 16.7ms)
Started GET "/settings" for 127.0.0.1 at 2016-06-26 03:39:59 -0500
Processing by Devise::RegistrationsController#edit as HTML
User Load (1.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ORDER BY "users"."id" ASC LIMIT [["id", 1547], ["LIMIT", 1]]
Rendering devise/registrations/edit.html.erb within layouts/application
Rendered devise/registrations/edit.html.erb within layouts/application (16.7ms)
Rendered shared/_navbar.html.erb (2.8ms)
Rendered shared/_footer.html.erb (1.0ms)
Completed 200 OK in 184ms (Views: 180.4ms | ActiveRecord: 1.2ms)
Started GET "/users" for 127.0.0.1 at 2016-06-26 03:40:01 -0500
Processing by UsersController#index as HTML
User Load (2.4ms) SELECT "users".* FROM "users" WHERE "users"."id" = ORDER BY "users"."id" ASC LIMIT [["id", 1547], ["LIMIT", 1]]
Role Load (2.2ms) SELECT "roles".* FROM "roles" INNER JOIN "users_roles" ON "roles"."id" = "users_roles"."role_id" WHERE "users_roles"."user_id" = AND (((roles.name = 'admin') AND (roles.resource_type IS NULL) AND (roles.resource_id IS NULL))) [["user_id", 1547]]
Rendering users/index.html.erb within layouts/application
User Load (1.3ms) SELECT "users".* FROM "users"
Rendered users/index.html.erb within layouts/application (7.2ms)
Started GET "/users" for 127.0.0.1 at 2016-06-26 03:40:02 -0500
Processing by UsersController#index as HTML
User Load (2.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = ORDER BY "users"."id" ASC LIMIT [["id", 1547], ["LIMIT", 1]]
Role Load (3.8ms) SELECT "roles".* FROM "roles" INNER JOIN "users_roles" ON "roles"."id" = "users_roles"."role_id" WHERE "users_roles"."user_id" = AND (((roles.name = 'admin') AND (roles.resource_type IS NULL) AND (roles.resource_id IS NULL))) [["user_id", 1547]]
Rendering users/index.html.erb within layouts/application
User Load (51.5ms) SELECT "users".* FROM "users"
Rendered users/index.html.erb within layouts/application (55.1ms)
Rendered shared/_navbar.html.erb (3.4ms)
Rendered shared/_footer.html.erb (1.3ms)
Completed 200 OK in 533ms (Views: 488.8ms | ActiveRecord: 5.8ms)
但是当我注释掉这一行时:can :crud, User, id: user.id
,所以我只有 cannot :read, User
行,它使我无法访问所有内容,如下面的日志所示(这也是我不知道的)我不想)。
Started GET "/users" for 127.0.0.1 at 2016-06-26 03:45:39 -0500
Processing by UsersController#index as HTML
User Load (1.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = ORDER BY "users"."id" ASC LIMIT [["id", 1547], ["LIMIT", 1]]
Role Load (1.3ms) SELECT "roles".* FROM "roles" INNER JOIN "users_roles" ON "roles"."id" = "users_roles"."role_id" WHERE "users_roles"."user_id" = AND (((roles.name = 'admin') AND (roles.resource_type IS NULL) AND (roles.resource_id IS NULL))) [["user_id", 1547]]
Redirected to http://localhost:3000/
Completed 302 Found in 19ms (ActiveRecord: 2.4ms)
Started GET "/users" for 127.0.0.1 at 2016-06-26 03:45:39 -0500
Processing by UsersController#index as HTML
User Load (1.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ORDER BY "users"."id" ASC LIMIT [["id", 1547], ["LIMIT", 1]]
Role Load (2.8ms) SELECT "roles".* FROM "roles" INNER JOIN "users_roles" ON "roles"."id" = "users_roles"."role_id" WHERE "users_roles"."user_id" = AND (((roles.name = 'admin') AND (roles.resource_type IS NULL) AND (roles.resource_id IS NULL))) [["user_id", 1547]]
Redirected to http://localhost:3000/
Completed 302 Found in 24ms (ActiveRecord: 4.0ms)
那么我该如何实现我想要做的事情呢?
不确定,但是怎么样:
def initialize(user)
alias_action :create, :read, :update, :destroy, to: :crud
user ||= User.new # guest user (not logged in)
if user.has_role?(:admin)
can :manage, :all
else
cannot :read, User
can :crud, User, id: user.id
cannot :index, User
# cannot :read, :users unless user.has_role? :admin
end
end
这就是我的 ability.rb
的截断版本:
class Ability
include CanCan::Ability
def initialize(user)
alias_action :create, :read, :update, :destroy, to: :crud
user ||= User.new # guest user (not logged in)
if user.has_role?(:admin)
can :manage, :all
else
cannot :read, User
can :crud, User, id: user.id
# cannot :read, :users unless user.has_role? :admin
end
end
end
我的 UsersController
看起来像这样:
class UsersController < ApplicationController
load_and_authorize_resource
before_action :set_user, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!, except: [:show]
# truncated for brevity
end
所以在这里,我想做的是 User#Index
,我想将其限制为管理员用户。但与此同时,每个用户应该能够访问自己的用户页面。
当我尝试上面的方法时,这对我来说很有意义,我可以访问 /settings
作为 current_user
,但我仍然可以访问 Users#Index
这是我不想。
这是日志的样子:
Started GET "/users/1547" for 127.0.0.1 at 2016-06-26 03:39:57 -0500
DEPRECATION WARNING: before_filter is deprecated and will be removed in Rails 5.1. Use before_action instead. (called from <class:UsersController> at myapp/controllers/users_controller.rb:2)
Processing by UsersController#show as HTML
Parameters: {"id"=>"1547"}
User Load (2.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = LIMIT [["id", 1547], ["LIMIT", 1]]
User Load (1.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = ORDER BY "users"."id" ASC LIMIT [["id", 1547], ["LIMIT", 1]]
Role Load (1.8ms) SELECT "roles".* FROM "roles" INNER JOIN "users_roles" ON "roles"."id" = "users_roles"."role_id" WHERE "users_roles"."user_id" = AND (((roles.name = 'admin') AND (roles.resource_type IS NULL) AND (roles.resource_id IS NULL))) [["user_id", 1547]]
CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = LIMIT [["id", 1547], ["LIMIT", 1]]
Rendering users/show.html.erb within layouts/application
Rendered shared/_navbar.html.erb (2.4ms)
Rendered shared/_footer.html.erb (1.3ms)
Completed 200 OK in 244ms (Views: 196.4ms | ActiveRecord: 16.7ms)
Started GET "/settings" for 127.0.0.1 at 2016-06-26 03:39:59 -0500
Processing by Devise::RegistrationsController#edit as HTML
User Load (1.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ORDER BY "users"."id" ASC LIMIT [["id", 1547], ["LIMIT", 1]]
Rendering devise/registrations/edit.html.erb within layouts/application
Rendered devise/registrations/edit.html.erb within layouts/application (16.7ms)
Rendered shared/_navbar.html.erb (2.8ms)
Rendered shared/_footer.html.erb (1.0ms)
Completed 200 OK in 184ms (Views: 180.4ms | ActiveRecord: 1.2ms)
Started GET "/users" for 127.0.0.1 at 2016-06-26 03:40:01 -0500
Processing by UsersController#index as HTML
User Load (2.4ms) SELECT "users".* FROM "users" WHERE "users"."id" = ORDER BY "users"."id" ASC LIMIT [["id", 1547], ["LIMIT", 1]]
Role Load (2.2ms) SELECT "roles".* FROM "roles" INNER JOIN "users_roles" ON "roles"."id" = "users_roles"."role_id" WHERE "users_roles"."user_id" = AND (((roles.name = 'admin') AND (roles.resource_type IS NULL) AND (roles.resource_id IS NULL))) [["user_id", 1547]]
Rendering users/index.html.erb within layouts/application
User Load (1.3ms) SELECT "users".* FROM "users"
Rendered users/index.html.erb within layouts/application (7.2ms)
Started GET "/users" for 127.0.0.1 at 2016-06-26 03:40:02 -0500
Processing by UsersController#index as HTML
User Load (2.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = ORDER BY "users"."id" ASC LIMIT [["id", 1547], ["LIMIT", 1]]
Role Load (3.8ms) SELECT "roles".* FROM "roles" INNER JOIN "users_roles" ON "roles"."id" = "users_roles"."role_id" WHERE "users_roles"."user_id" = AND (((roles.name = 'admin') AND (roles.resource_type IS NULL) AND (roles.resource_id IS NULL))) [["user_id", 1547]]
Rendering users/index.html.erb within layouts/application
User Load (51.5ms) SELECT "users".* FROM "users"
Rendered users/index.html.erb within layouts/application (55.1ms)
Rendered shared/_navbar.html.erb (3.4ms)
Rendered shared/_footer.html.erb (1.3ms)
Completed 200 OK in 533ms (Views: 488.8ms | ActiveRecord: 5.8ms)
但是当我注释掉这一行时:can :crud, User, id: user.id
,所以我只有 cannot :read, User
行,它使我无法访问所有内容,如下面的日志所示(这也是我不知道的)我不想)。
Started GET "/users" for 127.0.0.1 at 2016-06-26 03:45:39 -0500
Processing by UsersController#index as HTML
User Load (1.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = ORDER BY "users"."id" ASC LIMIT [["id", 1547], ["LIMIT", 1]]
Role Load (1.3ms) SELECT "roles".* FROM "roles" INNER JOIN "users_roles" ON "roles"."id" = "users_roles"."role_id" WHERE "users_roles"."user_id" = AND (((roles.name = 'admin') AND (roles.resource_type IS NULL) AND (roles.resource_id IS NULL))) [["user_id", 1547]]
Redirected to http://localhost:3000/
Completed 302 Found in 19ms (ActiveRecord: 2.4ms)
Started GET "/users" for 127.0.0.1 at 2016-06-26 03:45:39 -0500
Processing by UsersController#index as HTML
User Load (1.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ORDER BY "users"."id" ASC LIMIT [["id", 1547], ["LIMIT", 1]]
Role Load (2.8ms) SELECT "roles".* FROM "roles" INNER JOIN "users_roles" ON "roles"."id" = "users_roles"."role_id" WHERE "users_roles"."user_id" = AND (((roles.name = 'admin') AND (roles.resource_type IS NULL) AND (roles.resource_id IS NULL))) [["user_id", 1547]]
Redirected to http://localhost:3000/
Completed 302 Found in 24ms (ActiveRecord: 4.0ms)
那么我该如何实现我想要做的事情呢?
不确定,但是怎么样:
def initialize(user)
alias_action :create, :read, :update, :destroy, to: :crud
user ||= User.new # guest user (not logged in)
if user.has_role?(:admin)
can :manage, :all
else
cannot :read, User
can :crud, User, id: user.id
cannot :index, User
# cannot :read, :users unless user.has_role? :admin
end
end