如何在 graphql 中使用本地护照

Posted

技术标签:

【中文标题】如何在 graphql 中使用本地护照【英文标题】:How to use passport-local with graphql 【发布时间】:2019-12-23 15:30:11 【问题描述】:

我正在尝试在我的项目中实现 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
    

问题:

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

【问题讨论】:

【参考方案1】:

Passport.js 是一个“与 Express 兼容的身份验证中间件”。 authenticate 返回一个 Express 中间件函数——它旨在防止对特定 Express 路由的未经授权的访问。它并不适合在解析器中使用。如果您通过上下文将req 对象传递给解析器,则可以调用req.login 手动登录用户,但您必须验证凭据并自己创建user 对象,然后再将其传递给函数。同样,您可以调用req.logout 手动注销用户。有关文档,请参阅 here。

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

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

【讨论】:

哇,非常感谢!这种护照-graphql 组合在现实生活中有多普遍?我有一种感觉,我可能不应该在这里使用护照。【参考方案2】:

我花了一些时间来理解 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。

【讨论】:

【参考方案3】:

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

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

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

为什么?

如果您使用的是客户端应用程序,那么基于令牌的身份验证是最佳做法。 使用passport 实现REST JWT 非常简单。您可以尝试按照@jkettmann 的描述在 GraphQL 中构建它,但它更复杂且支持更少。我不认为这样做会带来巨大的好处。 在 GraphQL 中实现 JWT 非常简单。参见例如对于express 或NestJS

对于您的问题:

护照主要是为 REST/Express 设计的吗?

原则上不是,但你会发现大多数关于 REST 和 express 的资源。

这甚至是一种常见的做法还是我应该坚持使用一些 JWT 库?

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


更多细节在这里:OAuth2 in NestJS for Social Login (Google, Facebook, Twitter, etc)

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

【讨论】:

当您使用 REST 登录时 - 您将如何将 HttpOnly cookie(带有 JWT 令牌)传递到 GraphQL 游乐场? 您可以在前端读取 cookie 并将其传递给 GraphQL 查询。更多详细信息:csaba-apagyi.medium.com/… 示例:github.com/thisismydesign/nestjs-starter

以上是关于如何在 graphql 中使用本地护照的主要内容,如果未能解决你的问题,请参考以下文章

如何在保存到数据库之前对密码进行哈希处理以与护照模块兼容(本地护照)

如何在同一端点上使用护照 js 本地和基本策略?

如何修复阻止注册用户登录的护照本地身份验证错误

在服务器端护照js本地用户身份验证后,如何在客户端使用cookie显示用户信息?

如何使用护照本地猫鼬更改密码?

如何在没有守卫装饰器的情况下始终验证 JWT? (Nest.js + 护照)