如何在 graphql 中使用 passport-local

How to use passport-local with graphql

我正在尝试在我的项目中实现 GraphQL,我想在我的登录 Mutation

中使用 passport.authenticate('local')

我要的代码适配:

const typeDefs = gql`
type Mutation {
      login(userInfo: UserInfo!): User
    }
`

 const resolvers = {
    Mutation: {
      login: (parent, args) => { 
        passport.authenticate('local')
        return req.user
    }
}

问题:

  1. passport 主要是为 REST/Express 设计的吗?
  2. 我可以操纵 passport.authenticate 方法(将用户名和密码传递给它)吗?
  3. 这是一种常见的做法还是我应该坚持使用某些 JWT 库?

Passport.js 是一个 "Express-compatible authentication middleware"。 authenticate returns 一个 Express 中间件功能 -- 它旨在防止对特定 Express 路由的未授权访问。它不太适合在解析器内部使用。如果你通过上下文将你的 req 对象传递给你的解析器,你可以调用 req.login 来手动登录用户,但是你必须在传递之前验证凭据并自己创建 user 对象它的功能。同样,您可以调用 req.logout 手动注销用户。有关文档,请参阅 here

如果你想使用 Passport.js,最好的办法是为你正在使用的每个身份提供商创建一个带有授权路由和回调路由的 Express 应用程序(参见 this举个例子)。然后使用 apollo-server-express 将 Express 应用与您的 GraphQL 服务集成。您的客户端应用程序将使用授权路由来初始化身份验证流程,回调端点将重定向回您的客户端应用程序。然后,您可以将 req.user 添加到您的上下文中,并在解析器、指令、GraphQL 中间件等中检查它

但是,如果您使用本地策略,您可能会考虑完全放弃 Passport,自己处理事情。

我花了一段时间才了解 GraphQL 和 Passport 的组合。尤其是当您想将本地策略与登录突变一起使用时,会使事情变得复杂。这就是为什么我创建了一个名为 graphql-passport.

的小 npm 包的原因

这是服务器设置的样子。

import express from 'express';
import session from 'express-session';
import { ApolloServer } from 'apollo-server-express';
import passport from 'passport';
import { GraphQLLocalStrategy, buildContext } from 'graphql-passport';

passport.use(
  new GraphQLLocalStrategy((email, password, done) => {
    // Adjust this callback to your needs
    const users = User.getUsers();
    const matchingUser = users.find(user => email === user.email && password === user.password);
    const error = matchingUser ? null : new Error('no matching user');
    done(error, matchingUser);
  }),
);

const app = express();
app.use(session(options)); // optional
app.use(passport.initialize());
app.use(passport.session()); // if session is used

const server = new ApolloServer({
  typeDefs,
  resolvers,
  context: ({ req, res }) => buildContext({ req, res, User }),
});

server.applyMiddleware({ app, cors: false });

app.listen({ port: PORT }, () => {
  console.log(` Server ready at http://localhost:${PORT}${server.graphqlPath}`);
});

现在您将可以通过 GraphQL 上下文访问护照特定功能和用户。这是您可以编写解析器的方式:

const resolvers = {
  Query: {
    currentUser: (parent, args, context) => context.getUser(),
  },
  Mutation: {
    login: async (parent, { email, password }, context) => {
      // instead of email you can pass username as well
      const { user } = await context.authenticate('graphql-local', { email, password });

      // only required if express-session is used
      context.login(user);

      return { user }
    },
  },
};

GraphQL 和 Passport.js 的结合很有意义。特别是如果您想添加更多身份验证提供程序,如 Facebook、Google 等。如果需要,您可以找到更详细的信息 in this blog post

除非您的目标是深入了解身份验证,否则您绝对应该使用 passport

我发现将 passport 与 GraphQL 集成的最直接的方法是:

  • 使用 JWT 策略
  • 保留 REST 端点以验证和检索令牌
  • 将令牌发送到 GraphQL 端点并在后端对其进行验证

为什么?

  • 如果您使用的是客户端应用程序,那么基于令牌的身份验证无论如何都是最佳做法。
  • 使用 passport 实现 REST JWT 很简单。您可以尝试按照@jkettmann 的描述在 GraphQL 中构建它,但它更复杂且支持更少。我看不到这样做有什么好处。
  • 在 GraphQL 中实现 JWT 很简单。参见例如express or NestJS

你的问题:

Was passport designed mostly for REST/Express?

原则上不会,但您会找到大多数关于 REST 和 express 的资源。

Is this even a common practice or I should stick to some JWT library?

通常的做法是坚持使用 JWT。


此处有更多详细信息:OAuth2 in NestJS for Social Login (Google, Facebook, Twitter, etc)

此处的示例项目:https://github.com/thisismydesign/nestjs-starter