2016-05-20 5 views
10

ユーザーがへのアクセス許可を持っているかどうかを確認するには、またはクエリを参照してください。私はこれをどうやって行うのか分かりません。 argsGraphQLクエリの権限とその他の条件をチェックする方法は?

  • ?それはどのように働くでしょうか?
  • resolve()?ユーザーに権限があるかどうか確認してください。 argsの一部を削除/変更しますか?

例:

ユーザーは "訪問者" であれば、彼は唯一の公共の投稿を見ることができ、 "管理者" のすべてを見ることができます。

const userRole = 'admin'; // Let's say this could be "admin" or "visitor" 

const Query = new GraphQLObjectType({ 
    name: 'Query', 
    fields:() => { 
     return { 
      posts: { 
       type: new GraphQLList(Post), 
       args: { 
        id: { 
         type: GraphQLString 
        }, 
        title: { 
         type: GraphQLString 
        }, 
        content: { 
         type: GraphQLString 
        }, 
        status: { 
         type: GraphQLInt // 0 means "private", 1 means "public" 
        }, 
       }, 

       // MongoDB/Mongoose magic happens here 
       resolve(root, args) { 
        return PostModel.find(args).exec() 
       } 
      } 
     } 
    } 
}) 

更新 - マングースモデルは次のようになります。

import mongoose from 'mongoose' 

const postSchema = new mongoose.Schema({ 
    title: { 
     type: String 
    }, 
    content: { 
     type: String 
    }, 
    author: { 
     type: mongoose.Schema.Types.ObjectId, // From user model/collection 
     ref: 'User' 
    }, 
    date: { 
     type: Date, 
     default: Date.now 
    }, 
    status: { 
     type: Number, 
     default: 0 // 0 -> "private", 1 -> "public" 
    }, 
}) 

export default mongoose.model('Post', postSchema) 

答えて

12

あなたは解決機能やモデルレイヤにおけるユーザーの許可を確認することができます。あなたが取らなければならない手順は次のとおりです。

  1. クエリを実行する前にユーザーを認証します。これはあなたのサーバによって異なります。通常、リクエストとともに送信されたクッキーを見るなど、graphqlの外部で行われます。 Passport.jsを使用してこれを行う方法の詳細については、this Medium postを参照してください。
  2. 認証されたユーザーオブジェクトまたはユーザーIDをコンテキストに追加します。エクスプレス・graphqlであなたはcontext引数を経由してそれを行うことができます。

    app.use('/graphql', (req, res) => { 
        graphqlHTTP({ schema: Schema, context: { user: req.user } })(req, res); 
    } 
    
  3. 次のように解決関数内のコンテキストを使用してください:あなたは解決機能で直接認証チェックを行うことができます

    resolve(parent, args, context){ 
        if(!context.user.isAdmin){ 
        args.isPublic = true; 
        } 
        return PostModel.find(args).exec(); 
    } 
    

モデルレイヤーを持っている場合は、そのモデルレイヤーにユーザーオブジェクトを渡して実装することを強くお勧めします。そうすれば、コードはモジュール化され、再利用が容易になり、リゾルバのどこかのチェックを忘れることを心配する必要はありません。認可に関する詳細な背景については

、(これも自分で書かれた)この記事をチェックアウト:私たちは私たちの会社で承認を解決する助けている Auth in GraphQL - part 2

+1

Mongooseを使用している場合は、解決機能のチェックを行うのが最も簡単です。私はMongooseをよく知っているわけではありませんが、もう少し前にMongooseとSQLiteを使ったGraphQLサーバチュートリアルを書いています。 express-graphqlの代わりにapolloServerを使用します。これは少し違って見えますが、解決関数とデータフェッチの場合、すべてがほぼ同じです。 [こちら](https://medium.com/apollo-stack/tutorial-building-a-graphql-server-cdda023c035)にあります。 – helfer

+1

ええ、あなたはnullを返すか、エラーを投げることができ、GraphQLはそのクエリの分岐を停止します。データベース内の項目(ロールなど)に基づいて権限をチェックする必要がある場合は、約束を結ぶことができます。最初にアイテムとそのアイテムに関連する権限を取得し、それが返されたときにユーザが権限を持っているかどうかをチェックします。ユーザーに権限がない場合は、エラーをスローするか、nullを返します。ユーザーに許可がある場合は、アイテム(またはそのようなもの)を返します。 – helfer

8

一つのアプローチは、ミドルウェアの組成物としてのレゾルバについて考えることです。上記の例は素晴らしいですが、認可メカニズムが高度化するにつれて規模が大きくなることはありません。

ミドルウェアの組成物としてのレゾルバの例は次のようになります。

type ResolverMiddlewareFn = 
    (fn: GraphQLFieldResolver) => GraphQLFieldResolver; 

ResolverMiddlewareFnGraphQLFieldResolverを取り、そしてGraphQLFieldResolverを返す関数です。

リゾルバのミドルウェア関数を構成するには、compose関数を使用します(あなたが推測すると)!ここではexample of composeがjavascriptで実装されていますが、ramdaと他の機能ライブラリでも作成機能を見つけることができます。 Composeでは、より複雑な関数を作成するための単純な関数を組み合わせることができます。

GraphQLの権限の問題に戻ると、簡単な例を見ることができます。 リゾルバーにログを記録し、ユーザーを認証して、肉とジャガイモを実行したいとします。 Composeは、これらの3つの要素を組み合わせて、アプリケーション全体で容易にテストして再利用できるようにします。

const traceResolve = 
    (fn: GraphQLFieldResolver) => 
    async (obj: any, args: any, context: any, info: any) => { 
    const start = new Date().getTime(); 
    const result = await fn(obj, args, context, info); 
    const end = new Date().getTime(); 
    console.log(`Resolver took ${end - start} ms`); 
    return result; 
    }; 

const isAdminAuthorized = 
    (fn: GraphQLFieldResolver) => 
    async (obj: any, args: any, context: any, info: any) => { 
    if (!context.user.isAdmin) { 
     throw new Error('User lacks admin authorization.'); 
    } 
    return await fn(obj, args, context, info); 
    } 

const getPost = (obj: any, args: any, context: any, info: any) => { 
    return PostModel.find(args).exec(); 
} 

const getUser = (obj: any, args: any, context: any, info: any) => { 
    return UserModel.find(args).exec(); 
} 

// You can then define field resolve functions like this: 
postResolver: compose(traceResolve, isAdminAuthorized)(getPost) 

// And then others like this: 
userResolver: compose(traceResolve, isAdminAuthorized)(getUser) 
+0

すばらしい答え!おかあさんマイケル –

関連する問題