【问题标题】:How to implement Authorization with Custom Directives in apollo with graphql-tools/utils?如何使用 graphql-tools/utils 在 apollo 中使用自定义指令实现授权?
【发布时间】:2022-08-20 04:20:42
【问题描述】:

我知道 Apollo 2 通过扩展类“SchemaDirectiveVisitor”来允许自定义指令。但是,我正在使用 apollo 3,并且我知道现在实现这一点的方法是使用 graphql-tools/utils 和 graphql-tools/schema。

在我的 index.js 中,我有以下代码:

const serverServer = async () => {
   app.use(AuthMiddleware);

   app.use(
      cors({
         origin: \'mydomain\',
      })
   );

   let schema = makeExecutableSchema({
      typeDefs: [typeDefsLibrary, typeDefsDynamicContent, userTypeDefs],
      resolvers: {
         Query,
         Mutation,
         Article,
         Blog,
         Podcast,
         SermonNotes,
         Sermon,
         // dynamic Content
         Friday,
         Thursday,
         // Post Content
         Commentary,
         Quote,
         Thought,
         UserContent_SermonNotes,
         // User Content
         User,
         All_Posts,
      },
   });

   schema = AuthorizationDirective(schema, \'auth\');

   const apolloServer = new ApolloServer({
      schema,
      context: ({ req }) => {
         const { isAuth, user } = req;
         return {
            req,
            isAuth,
            user,
         };
      },
   });

   await apolloServer.start();
   apolloServer.applyMiddleware({ app: app, path: \'/api\' });

   app.listen(process.env.PORT, () => {
      console.log(`listening on port 4000`);
   });
};

serverServer();

然后在我的模式文件上我有:

  directive @auth(requires: [RoleName] ) on OBJECT | FIELD_DEFINITION 
  
  enum RoleName {
    SUPERADMIN
    ADMIN
  }

   type Commentary @auth(requires: [SUPERADMIN, ADMIN]) {
      ID: ID
      USER_ID: ID
      VERSE_ID: String
      body: String
      category_tags: String
      referenced_verses: String
      verse_citation: String
      created_date: String
      posted_on: String
      creator(avatarOnly: Boolean): User
      comments(showComment: Boolean): [Commentary_Comment]
      approvals: [Commentary_Approval]
      total_count: Int
   }

这是我的自定义指令代码:

const { mapSchema, getDirective, MapperKind } = require(\'@graphql-tools/utils\');
const { defaultFieldResolver } = require(\'graphql\');
const { ApolloError } = require(\'apollo-server-express\');
//const { logging } = require(\'../../helpers\');

module.exports.AuthorizationDirective = (schema, directiveName) => {
   return mapSchema(schema, {
      [MapperKind.FIELD]: (fieldConfig, _fieldName, typeName) => {
         const authDirective = getDirective(schema, fieldConfig, directiveName);
         console.log(\'auth Directive line 10: \', authDirective);
         if (authDirective && authDirective.length) {
            const requiredRoles = authDirective[0].requires;

            if (requiredRoles && requiredRoles.length) {
               const { resolve = defaultFieldResolver } = fieldConfig;
               fieldConfig.resolve = function (source, args, context, info) {
                  if (requiredRoles.includes(\'PUBLIC\')) {
                     console.log(
                        `==> ${context.code || \'ANONYMOUS\'} ACCESSING PUBLIC RESOLVER: ${
                           info.fieldName
                        }`
                     );
                     //logging(context, info.fieldName, args);

                     return resolve(source, args, context, info);
                  }

                  if (!requiredRoles.includes(context.code)) {
                     throw new ApolloError(\'NOT AUTHORIZED\', \'NO_AUTH\');
                  }
                  console.log(`==> ${context.code} ACCESSING PRIVATE RESOLVER: ${info.fieldName}`);
                  //logging(context, info.fieldName, args);

                  return resolve(source, args, context, info);
               };

               return fieldConfig;
            }
         }
      },
   });
};

但不工作。似乎它甚至没有调用自定义指令。如您所见,我的架构指令函数上有一个 \"console.log(\'auth Directive line 10: \', authDirective);\" ,它返回 \"undefined.\"

我知道这篇文章很长,但我希望有人能提供帮助!

提前致谢!

    标签: reactjs graphql apollo apollo-server


    【解决方案1】:

    下面是为我工作的代码

    我使用过 [MapperKind.OBJECT_FIELD]:而不是 [MapperKind.FIELD]:

    我从@graphql-tools 提到了这个-> https://www.graphql-tools.com/docs/schema-directives#enforcing-access-permissions

    ` const { mapSchema, getDirective, MapperKind } = require('@graphql-tools/utils'); const { defaultFieldResolver } = require('graphql');

    const HasRoleDirective = (schema, directiveName) => { 返回地图架构(架构,{

    // Executes once for each object field in the schems
    [MapperKind.OBJECT_FIELD]: (fieldConfig, _fieldName, typeName) => {
    
      // Check whether this field has the specified directive
      const authDirective = getDirective(schema, fieldConfig, directiveName);
    
      if (authDirective && authDirective.length) {
        const requiredRoles = authDirective[0].requires;
        // console.log("requiredRoles: ", requiredRoles);
    
        if (requiredRoles && requiredRoles.length) {
          // Get this field's original resolver
          const { resolve = defaultFieldResolver } = fieldConfig;
    
          // Replace the original resolver with function that "first" calls 
          fieldConfig.resolve = function (source, args, context, info) {
            // console.log("Context Directive:  ", context);
            const { currentUser } = context;
            if(!currentUser) throw new Error("Not Authenticated");
    
            const { type } = currentUser['userInfo']
            const isAuthorized = hasRole(type, requiredRoles);
            if(!isAuthorized) throw new Error("You Have Not Enough Permissions!")
    
            //logging(context, info.fieldName, args);
            return resolve(source, args, context, info);
          };
          return fieldConfig;
        }
      }
    }
    

    }) } `

    【讨论】:

      猜你喜欢
      • 2021-06-18
      • 2020-02-22
      • 2018-12-24
      • 2020-03-21
      • 2011-04-24
      • 2020-06-03
      • 2020-08-20
      • 1970-01-01
      • 2019-05-28
      相关资源
      最近更新 更多