KASHIMURA Blog

Webサービス開発のこと、個人的なことを書いているブログ

graphql-rubyで認証の有無を判断して処理を分ける

f:id:kasssssy:20201128134441p:plain

はじめに

GraphQLをRails APIで採用する時、認証の有無で処理を分ける方法です。
実装方法は何パターンかあるみたいですが、自分はオペレーション名を見て認証が必要なオペレーションが1つ以上存在するなら認証処理を行うようにしました。
GraphQLを利用するためにgem graphql-rubyを利用しています。

こうした

GraphqlControllerのexecuteのcontextを次のように修正

def execute
  variables = prepare_variables(params[:variables])
  query = params[:query]
  operation_name = params[:operationName]
  context = { current_user: auth_free?(query) ? nil : current_user }
 ... 

auth_free?()は認証の有無を判断するメソッド。
オペレーションの名前を確認してbooleanを返す。
current_userは認証処理を実行して現在のユーザー情報を取得するメソッド。
firebase authのjwt認証などはこのメソッド内で行う。

auth_free?(query)メソッドの中身

def auth_free?(query)
  if query.blank?
    # エラー返す処理など
    ...
  end

  parsed_query = GraphQL.parse(query)
  operations = parsed_query.definitions.select { |q| q.is_a?(GraphQL::Language::Nodes::OperationDefinition) }

  auth_free_operation_names = %w[
    createUser
  ] 

  operations.each do |operation|
    return false if operation.selections.find { |o| auth_free_operation_names.exclude?(o.name) }
  end

  true
end

・最初にクエリーの存在を確認して、存在しなかったらエラーを返すなどを行う。

GraphQL.parse(query)で文字列のQueryをパースしてOperationの情報を取得できるようにする。
・パースした結果から対象のGraphQL::Language::Nodes::OperationDefinition型のオブジェクトを取得する。

auth_free_operation_namesは、認証を不要とするオペレーション名を配列で保持。

・最後に1つでも認証が必要なオペレーションが存在していたらfalse(認証必要)を返す。
・そうでなければtrue(認証不要)を返す。