好的,我的系统中有User
,Book
和Chapter
个实体。
如果作者(User
实体)发布了一本书和一章,那么它可供公众查看。让我们致电作者吉姆。
这意味着如果另一位名叫Tycus的普通用户想要阅读Jim的书籍和书籍章节,他应该能够这样做。
我正在使用Pundit gem(https://github.com/elabs/pundit)获取权限。
我面临的问题是,当Tycus试图访问Jim的书时,看来我的Rails正试图获取链接关系(chapter --> book --> author
)及其:
Started GET "//books/16" for ::1 at 2016-12-16 23:29:38 +0800
Processing by BooksController#show as JSON
Parameters: {"id"=>"16"}
User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 21], ["LIMIT", 1]]
Book Load (0.1ms) SELECT "books".* FROM "books" WHERE "books"."id" = ? LIMIT ? [["id", 16], ["LIMIT", 1]]
Role Load (0.1ms) SELECT "roles".* FROM "roles" WHERE "roles"."id" = ? LIMIT ? [["id", 3], ["LIMIT", 1]]
[active_model_serializers] User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 2], ["LIMIT", 1]]
[active_model_serializers] Chapter Load (0.1ms) SELECT "chapters".* FROM "chapters" WHERE "chapters"."book_id" = ? [["book_id", 16]]
[active_model_serializers] Genre Load (0.1ms) SELECT "genres".* FROM "genres" INNER JOIN "books_genres" ON "genres"."id" = "books_genres"."genre_id" WHERE "books_genres"."book_id" = ? [["book_id", 16]]
[active_model_serializers] Love Load (0.1ms) SELECT "loves".* FROM "loves" WHERE "loves"."book_id" = ? [["book_id", 16]]
[active_model_serializers] Rendered BookSerializer with ActiveModelSerializers::Adapter::JsonApi (30.04ms)
Completed 200 OK in 48ms (Views: 29.6ms | ActiveRecord: 2.0ms)
Started GET "//chapters/5" for ::1 at 2016-12-16 23:29:38 +0800
Processing by ChaptersController#show as JSON
Parameters: {"id"=>"5"}
User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 21], ["LIMIT", 1]]
Chapter Load (0.1ms) SELECT "chapters".* FROM "chapters" WHERE "chapters"."id" = ? LIMIT ? [["id", 5], ["LIMIT", 1]]
Book Load (0.1ms) SELECT "books".* FROM "books" WHERE "books"."id" = ? LIMIT ? [["id", 16], ["LIMIT", 1]]
Started GET "//chapters/7" for ::1 at 2016-12-16 23:29:38 +0800
Started GET "//chapters/6" for ::1 at 2016-12-16 23:29:38 +0800
[active_model_serializers] User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 2], ["LIMIT", 1]]
Processing by ChaptersController#show as JSON
Processing by ChaptersController#show as JSON
Started GET "//users/2" for ::1 at 2016-12-16 23:29:38 +0800
[active_model_serializers] Rendered ChapterSerializer with ActiveModelSerializers::Adapter::JsonApi (10.73ms)
Parameters: {"id"=>"7"}
Parameters: {"id"=>"6"}
Processing by UsersController#show as JSON
Completed 200 OK in 24ms (Views: 14.2ms | ActiveRecord: 0.9ms)
User Load (0.8ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 21], ["LIMIT", 1]]
User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 21], ["LIMIT", 1]]
Parameters: {"id"=>"2"}
Chapter Load (0.2ms) SELECT "chapters".* FROM "chapters" WHERE "chapters"."id" = ? LIMIT ? [["id", 7], ["LIMIT", 1]]
Chapter Load (0.2ms) SELECT "chapters".* FROM "chapters" WHERE "chapters"."id" = ? LIMIT ? [["id", 6], ["LIMIT", 1]]
User Load (0.7ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 21], ["LIMIT", 1]]
Book Load (0.1ms) SELECT "books".* FROM "books" WHERE "books"."id" = ? LIMIT ? [["id", 16], ["LIMIT", 1]]
Book Load (0.1ms) SELECT "books".* FROM "books" WHERE "books"."id" = ? LIMIT ? [["id", 16], ["LIMIT", 1]]
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 2], ["LIMIT", 1]]
[active_model_serializers] User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 2], ["LIMIT", 1]]
[active_model_serializers] User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 2], ["LIMIT", 1]]
Role Load (0.2ms) SELECT "roles".* FROM "roles" WHERE "roles"."id" = ? LIMIT ? [["id", 3], ["LIMIT", 1]]
[active_model_serializers] Rendered ChapterSerializer with ActiveModelSerializers::Adapter::JsonApi (6.75ms)
[active_model_serializers] Rendered ChapterSerializer with ActiveModelSerializers::Adapter::JsonApi (5.92ms)
Completed 403 Forbidden in 16ms (ActiveRecord: 1.0ms)
Completed 200 OK in 22ms (Views: 9.9ms | ActiveRecord: 1.6ms)
Completed 200 OK in 20ms (Views: 7.9ms | ActiveRecord: 1.0ms)
Pundit::NotAuthorizedError (not allowed to show? this #<User id: 2, first_name: "James", last_name: "Raynor", username: "Jimmy", email: "chewedon+jim@gmail.com", password_digest: "$2a$10$9xCQKiku7YD.xjzbj34/P.4JUHCOf4lKXbVeqKy2PNb...", banned: false, role_id: 3, created_at: "2016-12-01 13:56:30", updated_at: "2016-12-11 08:31:42", photo: "jim_raynor.jpg", email_confirmed: true, confirm_token: nil, password_reset_token: nil>):
app/controllers/users_controller.rb:33:in `show'
结果,Pundit正在筹集Pundit::NotAuthorizedError
,因为它认为我试图访问用户的信息。
我的Emberjs前端合理地引起了这个例外:
我的Chapter_Controller
肯定没有明确要求提供作者的信息:
def show
chapter = Chapter.find_by(id: params[:id])
if chapter.present?
authorize chapter
render json: chapter
else
skip_authorization
render status: :not_found
end
end
我可以通过修改User
政策show?
方法来修复此错误,以便返回true
:
def show?
true
end
我的show?
方法目前是这样的:
def show?
# Allowing admins to view other admins (but do not allow update or deleting other admins)
if @user.superuser? || @record.id == @user.id || (@user.admin? && !@record.superuser?)
return true
elsif (@record.id != @user.id)
return false
end
end
但是这会将我的用户信息暴露给任何人看。例如,让我们说作者不想透露他们的真实姓名,只是他们的用户名(也许作者对他/她的书卖得不太自信,所以使用别名{{1}隐藏自己的身份。)
通过在我的用户策略show方法中指定username
,任何已登录的用户都可以向true
发出GET请求,并查看作者的详细信息。
所以我的问题是 - 有没有办法允许其他用户查看作者的书籍和书籍章节,但同时又不允许其他用户查看作者的个人信息?
看来我的活动模型序列化程序是试图提取用户记录的那个。
我认为在活动模型序列化程序github页面上发生了类似的讨论:https://github.com/rails-api/active_model_serializers/issues/1552
http://localhost:3000/users/{author_id}
def show?
# superuser and admins should respect author's privacy
# and not be able to view author's unpublished works
owner? || @record.published
end
def owner?
@record.book.author_id == @user.id
end
属于Chapter
而Book
属于Book
。
ChapterPolicy#show是如何定义的?该方法是否引用了 UserPolicy类? (如果是这样,请不要这样做!)
好的......如果我不检查当前登录的用户是否是作者,我还能如何限制未发布的章节仅对本书的作者可见?
如果有任何帮助,我的章节,书籍和用户的Active Model Serializer如下:
章:
User
图书:
class ChapterSerializer < ActiveModel::Serializer
attributes :id, :title, :order, :content, :published, :picture
attribute :content, if: :content_author?
belongs_to :book
def content_author?
# ---------------------------------------------------------
# Only author of the content can view their unpublished
# chapter content. Other users including superuser, admin
# and other normal users should not be able to view
# author's unpublished chapter content, even during
# admin/superuser updating author's chapter operation.
#
# We want to respect author's privacy and entitlement
# to publishing their story whenever they feel it's ready.
# ---------------------------------------------------------
if current_user != object.book.author && !object.published
return false
else
return true
end
end
end
用户:
class BookSerializer < ActiveModel::Serializer
attributes :id, :title, :blurb, :adult_content, :published, :cover
belongs_to :author, class_name: "User"
has_many :chapters
has_many :genres
has_many :loves
end
答案 0 :(得分:0)
您的问题是由于模型的相关性:
class ChapterSerializer < ActiveModel::Serializer
belongs_to :book
end
class BookSerializer < ActiveModel::Serializer
belongs_to :author, class_name: "User"
end
在您的前端应用程序的某个地方,您要求提供有关该书作者的信息 - 它不清楚这是什么信息,但是例如您可能正在查找&#34;其他本作者的书籍&#34;?
这会触发对/users/:id
的GET请求,由于您403
的实施,该请求会返回UserPolicy#show?
。
您的问题没有单一的答案,因为它有点是您需要做的架构设计问题/决定。但是,例如,可能的方法是允许用户始终可见:
class UserPolicy
def show?
true
end
end
...在您的UserSerializer
中,根据current_user
有条件地定义返回哪些属性。