【问题标题】:Basic authentication with GraphQL使用 GraphQL 进行基本身份验证
【发布时间】:2020-11-08 14:47:49
【问题描述】:

我在尝试查询使用 基本身份验证的 graphQL API 时收到此错误: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access.

我创建网络接口的代码是:

networkInterface = createNetworkInterface({
    uri: graphQlEndpoint.uri,
    opts: {
      credentials: graphQlEndpoint.credentials
    }
  });

  networkInterface.use([{
    applyMiddleware(req, next) {
      if (!req.options.header) {
        req.options.headers = {};
      }
      req.options.headers.authorization = 'Basic authorizationCode';
      next();
  }
}])

我猜这里的问题是,在我的 webapp 进行查询之前,它会发送一个预检请求,这就是我收到 错误 401 的地方。我想知道这是否真的是我在那里出错的原因。

如果是这样,有没有办法解决它?

在这种情况下,是否有另一种比基本身份验证更有效的身份验证?

注意:我正在使用 node.jsreactapollo-client

感谢您能给我的任何帮助。

编辑

// Enable Cross Origin Resource Sharing 
app.use('*', cors());

// Authorization: a user authentication is required
app.use((req, res, next) => {
  if (!getAuthUserName(req)) {
    logger('ERROR', 'Unauthorized: authenticated username is missing');
    res.status(401);
    res.send('Unauthorized: Access is denied due to missing credentials');
   }else {
    next();
   }
});

// Print Schema endpoint
app.use(rootUrl + '/schema', (req, res) => {
  res.set('Content-Type', 'text/plain');
  res.send(schemaPrinter.printSchema(schema));
});

// Print Introspection Schema endpoint
app.use(rootUrl + '/ischema', (req, res) => {
  res.set('Content-Type', 'text/plain');
  res.send(schemaPrinter.printIntrospectionSchema(schema));
});

// Stop node app
if (config.graphql.debugEnabled) {
  app.use(rootUrl + '/stop', (req, res) => {
    logger('INFO', 'Stop request');
    res.send('Stop request initiated');
    process.exit();
  });
}

// GraphQL endpoint
app.use(rootUrl, graphqlExpress(request => {
  const startTime = Date.now();

  request.uuid = uuidV1();
  request.workflow = {
    service: workflowService,
    context: getWorkflowContext(request)
  };
  request.loaders = createLoaders(config.loaders, request);
  request.resolverCount = 0;
  request.logTimeoutError = true;

  logger('INFO', 'new request ' + request.uuid + ' by ' + request.workflow.context.authUserName);

  request.incrementResolverCount =  function () {
    var runTime = Date.now() - startTime;
    if (runTime > config.graphql.queryTimeout) {
      if (request.logTimeoutError) {
        logger('ERROR', 'Request ' + request.uuid + ' query execution timeout');
      }
      request.logTimeoutError = false;
      throw('Query execution has timeout. Field resolution aborted');
    }
    this.resolverCount++;
  };

  return !config.graphql.debugEnabled ?
    {
      schema: schema,
      context: request,
      graphiql: config.graphql.graphiqlEnabled
    } :
    {
      schema: schema,
      context: request,
      graphiql: config.graphql.graphiqlEnabled,
      formatError: error => ({
        message: error.message,
        locations: error.locations,
        stack: error.stack
      }),
      extensions({ document, variables, operationName, result }) {
        return {
          requestId: request.uuid,
          runTime: Date.now() - startTime,
          resolverCount: request.resolverCount,
          operationCount: request.workflow.context.operationCount,
          operationErrorCount:     request.workflow.context.operationErrorCount
        };
      }
    };
}));

【问题讨论】:

  • 您的客户端代码很好,但您可能需要在服务器端启用 cors。您可以发布您的节点 js 服务器的代码吗? (表达我猜?)
  • 您的猜测是有道理的,但我认为它已经启用。我不是自己写的,但我在我的问题中添加了我认为你想看看的代码部分。
  • 你保存了吗?没有看到任何新代码
  • 是的,抱歉,稍后更新。如果有任何其他部分可以帮助我知道。
  • 有趣..如果你把app.use('*', cors())改成app.use(cors())会发生什么

标签: authentication graphql apollo-client


【解决方案1】:

请尝试在 graphql 服务器端添加 cors。我在这里发布了一些代码。

const corsOptions = {
    origin(origin, callback){
        callback(null, true);
    },
    credentials: true
};
graphQLServer.use(cors(corsOptions));
var allowCrossDomain = function(req, res, next) {
    res.header('Access-Control-Allow-Origin', '*');
    res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
    res.header('Access-Control-Allow-Headers', 'Content-Type,Accept');
    next();
}
graphQLServer.use(allowCrossDomain);

我想这可能对你有帮助。

【讨论】:

  • 我编辑了我的服务器代码以添加您建议的代码(将 graphQLServer.use 替换为 app.use)但我仍然收到相同的 preflight request doesn't pass access control check 错误。
  • 当我直接从 localhost/graphql 查询我的 server 时,我得到了您在 allowCrossDomain 中添加的所有标头我的响应标头。但是,当我从 client 查询时,我的 Response Headers 中没有任何这些标头。
  • @petithomme 您是否在创建应用服务器后放置了此代码段?有时代码放置会产生差异
  • 我把它放在.start之后和所有app.use之前。我已经与app.use(cors()) 有一行,所以我将代码放在那里
  • 我认为问题可能是 IIS 阻止了我的 OPTIONS 预检请求,因为它没有授权标头。我正在寻找一种方法来配置我的 IIS,以便在预检请求后返回带有 status 200 的消息。
【解决方案2】:

您正在使用的 graphql 服务器正在拒绝浏览器发出的预检请求,以查看服务器是否会接受浏览器的请求。预检请求也称为OPTIONS 请求。

服务器只发送状态码 200。所以除了你看到的 CORS sn-p 之外,你还需要添加一个检查。

这是您可以在 express 应用程序中使用的 cors 中间件:

module.exports = (req, res, next) => {
  res.setHeader("Access-Control-Allow-Origin", "*");
  res.setHeader(
    "Access-Control-Allow-Methods",
    "OPTIONS, GET, POST, PUT, PATCH, DELETE"
  );
  res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
  //--------------OPTIONS-------------
  if (req.method === "OPTIONS") {
    return res.sendStatus(200);
  }
  next();
};

【讨论】:

    猜你喜欢
    • 2015-08-12
    • 2017-06-13
    • 2013-05-30
    • 2016-05-31
    • 2017-10-06
    • 2013-09-14
    • 2010-12-11
    • 2016-08-24
    • 2017-08-01
    相关资源
    最近更新 更多