关于GraphQL Ruby的visible?和authorized?函数
GraphQL使用Mutation和Query的对象和字段等来进行授权。
这样,无论发出什么查询,我们都可以通过检查每个字段、对象等的权限来确定用户是否具有查看权限,并返回结果。
在上下文中,我会获取用户的信息并进行认证。
在业务逻辑层进行许可设置
在这篇文章中,我们将讨论GraphQL Ruby的Visibility和Authorization。然而,在考虑使用这种GraphQL层面的授权之前,我们应该先考虑在业务逻辑层面进行授权。
通过在模型中编写逻辑,无需为每个字段编写相同的处理程序。
class Post < ActiveRecord::Base
def self.posts_for(user)
if user.admin?
self.all
else
self.published
end
end
end
field :posts, [Types::Post], null: false
def posts
Post.posts_for(context[:current_user])
end
GraphQL 在权限层面实施认证也有其优势之处。它可以进一步确保 API 层面的安全性,并且可以在执行之前进行授权。
在GraphQL Ruby中,有Visibility和Authorization功能,我将对这两个功能进行说明。
可见性 和 授权
每一种都可以根据用户权限设置对某个领域或对象(类型类)的可访问信息的限制。每种都具有以下特点:
-
- Visibility: visible?
スキーマの一部を隠すことができる
権限のないユーザーが参照しようとするとバリデーションエラーを返す
Authorization: authorized?
権限のないユーザーも、fieldやobjectをIntrospectionで見ることができる
権限のないユーザーが参照しようとするとnilを返す
“visible?”是GraphQL Ruby的功能,而不是GraphQL规范的一部分。
它被设计用于在开发中隐藏不希望一般用户知道的功能,并仅对特定成员进行公开。
我们可以分别为object、field、引数等定义和设置visible?和authorized?方法。
领域
我们将对字段进行单元测试,以验证隐藏和授权设置。
我们在BaseField中定义visible?和authorized?方法。
当每个方法返回false时,用户将无法查看该字段。
module Types
class BaseField < GraphQL::Schema::Field
argument_class Types::BaseArgument
def initialize(*args, admin_only_visible: false, admin_only_authorized: false, **kwargs, &block)
@admin_only_visible = admin_only_visible
@admin_only_authorized = admin_only_authorized
super(*args, **kwargs, &block)
end
def visible?(ctx)
super && (@admin_only_visible ? ctx[:current_user]&.admin? : true)
end
def authorized?(obj, args, ctx)
super && (@admin_only_authorized ? ctx[:current_user]&.admin? : true)
end
end
end
当在需要限制的字段上分别设置admin_only_visible和admin_only_authorized时,仅管理员用户可以查看该字段。
module Types
class UserType < Types::BaseObject
field :id, ID, null: false
- field :name, String, null: false
- field :email, String, null: true
+ field :name, String, null: false, admin_only_visible: true
+ field :email, String, null: true, admin_only_authorized: true
end
end
通过这个,可以对管理员用户进行以下参考。

如果不是管理员的话,根据name的visible?设置,字段将无法被引用并返回错误。

看到这个字段,我发现名称被隐藏了。

设置了”authorized?”的电子邮件字段不会报错,但会返回null。

物体
我們接下來試著設定Object。
module Types
class UserType < Types::BaseObject
field :id, ID, null: false
field :name, String, null: false
field :email, String, null: true
+ field :articles, ArticleType.connection_type, null: false
end
end
module Types
class ArticleType < Types::BaseObject
field :id, ID, null: false
field :title, String, null: false
field :body, String, null: false
field :author, Types::UserType, null: false
+ def self.visible?(context)
+ super && context[:current_user]&.admin?
+ end
+
+ # def self.authorized?(object, context)
+ # super && context[:current_user]&.admin?
+ # end
end
end
能看得見嗎?若是可見的話,就似乎不存在一個User的類型中的articles。
此外,不僅物件本身被隱藏,還可看出返回其類型的field也被隱藏了。

如果是经过授权的话,则不会报错,而是返回null。

授权?自定义错误。
当在设置了“authorized”属性的对象中引用字段时,通常情况下不会发生错误,而是返回null,但也可以自定义此行为。
通过在模式中进行设置,可以实现以下效果:
class MySchema < GraphQL::Schema
lazy_resolve(Promise, :sync)
mutation(Types::MutationType)
query(Types::QueryType)
default_max_page_size 20
use GraphQL::Dataloader
def self.unauthorized_object(error)
raise GraphQL::ExecutionError, "An object of type #{error.type.graphql_name} was hidden due to permissions"
end
def self.unauthorized_field(error)
raise GraphQL::ExecutionError, "The field #{error.field.graphql_name} on an object of type #{error.type.graphql_name} was hidden due to permissions"
end
end
看起来还可以添加错误信息。

请参考
-
- https://graphql.org/learn/thinking-in-graphs/#business-logic-layer
- https://graphql-ruby.org/authorization/overview.html