認証ロジックをビジネスロジック層に委譲する
認証は、特定のユーザー/セッション/コンテキストがアクションを実行したり、データの一部を表示したりする権限を持っているかどうかを記述するビジネスロジックの一種です。例えば
「作成者のみが自分の下書きを見ることができる」
この種の動作の適用は、ビジネスロジック層で行う必要があります。GraphQL層に認証ロジックを配置したくなるかもしれませんが、以下のように
var postType = new GraphQLObjectType({ name: ‘Post’, fields: { body: { type: GraphQLString, resolve: (post, args, context, { rootValue }) => { // return the post body only if the user is the post's author if (context.user && (context.user.id === post.authorId)) { return post.body; } return null; } } }});
「作成者が投稿を所有している」ことを、投稿のauthorId
フィールドが現在のユーザーのid
と等しいかどうかをチェックすることで定義していることに注目してください。問題点がわかりますか?サービスの各エントリポイントでこのコードを複製する必要があります。そして、認証ロジックが完全に同期されていない場合、ユーザーは使用するAPIによって異なるデータを見ることができてしまいます。これは大変です。! 認証の単一の真実のソースを持つことで、それを回避できます。
GraphQLを学習したりプロトタイプを作成したりする場合、リゾルバー内に認証ロジックを定義することは問題ありません。ただし、本番コードベースの場合は、認証ロジックをビジネスロジック層に委譲してください。次に例を示します。
//Authorization logic lives inside postRepositoryvar postRepository = require('postRepository');
var postType = new GraphQLObjectType({ name: ‘Post’, fields: { body: { type: GraphQLString, resolve: (post, args, context, { rootValue }) => { return postRepository.getBody(context.user, post); } } }});
上記の例では、ビジネスロジック層が呼び出し元にユーザーオブジェクトを提供することを要求していることがわかります。GraphQL.jsを使用している場合、ユーザーオブジェクトはリゾルバーの4番目の引数であるcontext
引数またはrootValue
に設定する必要があります。
ビジネスロジック層には、不透明なトークンまたはAPIキーではなく、完全にハイドレートされたユーザーオブジェクトを渡すことをお勧めします。こうすることで、リクエスト処理パイプラインの異なる段階で認証と承認という異なる関心事を処理できます。