Условная проблема потока в зависимости от свойств объекта с использованием аутентификации Auth0 и GraphQL - PullRequest
0 голосов
/ 14 апреля 2020

Я пытаюсь создать контекст graphql, защищенный с помощью Auth0, используя Typescript, который может поддерживать как аутентифицированные, так и публичные маршруты c.

У меня есть функция authValidate, которая возвращает объект с 3 различными возможностями: 1. Токен не предоставлен 2. Токен недействителен 3. Токен действителен, поэтому можно перейти к получению информации о пользователе

Таким образом, форма объекта будет одной из следующих ...

      { error: 'No token provided' }

      { error:
        { JsonWebTokenError: invalid token

      { decoded:
        { email: 'John',
 context: async ({ req }) => {
      const { authorization: token } = req.headers;      

      const res: any = await isTokenValid(token);

Мне нужно посоветовать, как мне следует кодировать поток. Если я вызываю res.error или res.decoded, res.error или res.decoded могут быть недействительными в любом случае, в зависимости от результата вызова isTokenValid

Оцените, если кто-то может мне в этом помочь. Заранее спасибо

1 Ответ

0 голосов
/ 14 апреля 2020

Мне удалось решить вопрос об условном потоке. Ниже мое решение, если оно кому-то поможет

index.ts

import * as express from "express";
import { ApolloServer, AuthenticationError } from "apollo-server-express";
import * as depthLimit from "graphql-depth-limit";
import { createServer } from "http";
import * as compression from "compression";
import * as cors from "cors";

import typeDefs from "./typeDefs";
import resolvers from "./resolvers";
// import { typeDefs, resolvers } from "./utils/temp_graph";
import { isTokenValid } from "./utils/authValidate";
import User from "./models/User";
import Task from "./models/Task";
import { findOrMakeUser } from "./utils/findOrMakeUser";
import "./config/db";

(async () => {
  const app = express();

  const server = new ApolloServer({
    validationRules: [depthLimit(7)],
    typeDefs,
    resolvers,
    context: async ({ req }) => {
      const token = req.headers.authorization || "";

      let currentUser = null;

      if (token) {
        const { error, decoded }: any = await isTokenValid(token);

        if (error) {
          throw new AuthenticationError("Invalid Token. Access Denied!");
        }

        currentUser = await findOrMakeUser(decoded.email);
      }

      return {
        req,
        currentUser,
        User,
        Task,
      };
    },
  });

  app.use(cors());
  app.use(compression());

  server.applyMiddleware({ app, path: "/graphql" });

  const httpServer = createServer(app);

  const PORT = process.env.PORT || 4000;

  httpServer.listen({ port: PORT }, (): void =>
    console.log(
      `\n?      GraphQL is now running on http://localhost:${PORT}/graphql`
    )
  );
})();

utils / authValidate.ts

require("dotenv").config();
import * as jwt from "jsonwebtoken";
import * as jwksClient from "jwks-rsa";

const client = jwksClient({
  jwksUri: `https://${process.env.AUTH0_DOMAIN}/.well-known/jwks.json`,
});

const options = {
  audience: process.env.AUTH0_CLIENTID,
  issuer: `https://${process.env.AUTH0_DOMAIN}/`,
  algorithms: ["RS256"],
};

function getKey(header: any, callback: any) {
  client.getSigningKey(header.kid, function (_: any, key: any) {
    const signingKey = key.publicKey || key.rsaPublicKey;
    callback(null, signingKey);
  });
}

async function isTokenValid(token: any) {
  if (token) {
    const result = new Promise((resolve, __) => {
      jwt.verify(token, getKey, options as any, (error, decoded) => {
        if (error) {
          resolve({ error });
        }
        if (decoded) {
          resolve({ decoded });
        }
      });
    });

    return result;
  }

  return { error: "No token provided" };
}

export { isTokenValid };

resolvers / middlewares.ts

const { skip } = require("graphql-resolvers");

export const isAuthenticated = async (
  _: any,
  __: any,
  { currentUser }: any
) => {
  if (!currentUser) {
    throw new Error("Access Denied! Please authenticate to proceed");
  }

  return skip;
};

utils / findOrMakeUser.ts

import User from "../models/User";

const findOrMakeUser = async (email: any) => {
  const user = await User.findOne({ email });

  if (!user) {
    const newUser = new User({ email });
    const result = await newUser.save();
    console.log("findOrMakeUser result", result);
    return result;
  }

  return user;
};

export { findOrMakeUser };
...