总结一下GraphQL-Ruby的授权机制
首先
最近我有机会使用GraphQL-Ruby来实现授权功能,所以我想总结一下。
术语上有认证和授权两个概念,但这次我们只涉及授权。(通常情况下,GraphQL不涉及认证)
给resolver和mutation添加授权
首先,我们将总结可用于resolver和mutation授权的方法。您可以在以下链接找到更多信息:https://graphql-ruby.org/mutations/mutation_authorization.html
准备好了吗?
准备好了吗?可以在解析器(resolver)或变更(mutation)中使用ready?方法。ready?方法会在执行变更前自动调用。如果返回值为false,将返回null,但更好的做法是引发GraphQL错误,就像示例一样。
class Mutations::PromoteEmployee < Mutations::BaseMutation
def ready?(**args) # argsはmutationの引数
if !context[:current_user].admin?
raise GraphQL::ExecutionError, "Only admins can run this mutation"
else
true
end
end
def resolver(**args)
# mutation実行
end
end
授权了吗?
突变/mutation对象还提供了authorized?方法。实际上,这个方法与ready?方法几乎有相同的功能。将上述的ready?替换为authorized?,同样也能正常工作。唯一的区别在于是否加载arguments。
当加载arguments时,指的是当定义了argument并通过employee_id来获取在loads中定义的Employee对象时,它会自动从数据库中获取(可能是这个意思)。
argument :employee_id, ID, required: true, loads: Types::Employee
如果按照上述情况,将获取由参数指定的id的员工对象。因此,可以利用authorized?方法,写成以下形式。
argument :employee_id, ID, required: true, loads: Types::Employee
def authorized?(employee:)
context[:current_user].manager_of?(employee)
end
给予对象类型授权
在GraphQL-Ruby中,具有关联的对象可以在客户端自由获取。这可能导致访问本应需要权限的资源,为了防止这种情况发生,可以通过为每个对象类型设置授权来进行总结。
使用”visible”吗?
https://graphql-ruby.org/authorization/visibility.html
visible?方法的作用是使模式本身对用户不可见。例如,可以考虑将实验性功能仅开放给特定用户的用例。
在下面的示例中,如果visible?方法的返回值为false,则将返回GraphQL错误。
class secretType < BaseObject
def self.visible?(context)
context[:current_user].admin?
end
field :hoge, Hoge, null: true
end
用得了 authorized 吗?
https://graphql-ruby.org/authorization/authorization.html
在这里,这个authorized?方法看起来像是用来进行授权的。从名字上来看,确实是这样的。
在下面的例子中,如果current_user等于object.user,那么会返回Object,如果不相等,则返回null。
class secretType < BaseObject
def self.authorized?(object, context)
context[:current_user] === object.user
end
field :hoge, Hoge, null: true
end
另外,如果想在authorized方法返回false时返回错误,可以在模式的顶层定义错误。
class MySchema < GraphQL::Schema
def self.unauthorized_object(error)
raise GraphQL::ExecutionError, "An object of type #{error.type.graphql_name} was hidden due to permissions"
end
end
使用范围
使用 `authorized?` 方法后,我们可以选择返回或不返回对象。但是,有时我们可能希望限制返回对象的用户范围。这种情况下,`scope` 方法非常有用。
在以下示例中,如果用户是管理员,则返回所有对象;否则,返回已发布的产品。
class prodcutType < BaseObject
def self.scope_items(items, context)
context[:current_user].admin? items : items.published
end
end
您可以通过 field 参数来定义是否应用此 scope。
field :products, [Types::Product] scope: true
如果返回值是数组,则默认为true,如果是值,则为false。
总而言之
上述是对GraphQL-Ruby授权的总结。由于GraphQL的授权相当复杂,所以我们希望能够彻底整理一下!