【问题标题】:GraphQl and passport session: access req.user when querying GraphQlGraphQl 和护照会话:查询 GraphQl 时访问 req.user
【发布时间】:2018-03-01 11:24:48
【问题描述】:

我有一个 GraphQl 服务器和一个反应前端。我使用护照和 LocalStrategy 来验证运行良好的用户,我可以成功登录现有用户。我还想使用护照会话来创建用户会话,以便稍后在我的 GraphQl 解析器中访问已登录的用户进行身份验证。我希望护照在成功验证用户身份后在会话中设置用户。但是在从客户端向服务器发送正确的凭据后,GraphQl 查询无法访问req.user

GraphQL 服务器代码如下所示:

import express from 'express';
import passport from 'passport';
import {Strategy as LocalStrategy} from 'passport-local';
import session from 'express-session';
import cors from 'cors';
import bodyParser from 'body-parser';
import models from './models';
import typeDefs from './schema';
import resolvers from './resolvers';
import { graphqlExpress, graphiqlExpress } from 'apollo-server-express';
import { makeExecutableSchema } from 'graphql-tools';

export const schema = makeExecutableSchema({
  typeDefs,
  resolvers,
});

const app = express();

app.use('*', cors({ origin: 'http://localhost:3000' }));

app.set('port', (process.env.PORT || 3001));

//--- Passport ----
app.use(session({ 
  saveUninitialized: true, 
  resave: false,
  secret: 'verysecretsecret'
}));
app.use(passport.initialize());
app.use(passport.session());

passport.serializeUser((user, done) => {
    done(null, user);
 });

passport.deserializeUser((user, done) => {
  done(null, user);
});

passport.use(new LocalStrategy(
  {
    usernameField: 'email',
    passwordField: 'password',
  },
  function(email, password, done) {
    models.User.findOne({
      where: {
          email: email
      }
    }).then(function(user) {
      if (user) {
        if (user.validPassword(password)) {
          return done(null, user);
        } else {
          return done(null, false);
        }
      } 
      return done(null, false);     
    });    
  }
));

//--- Routes ----
app.use('/graphiql', graphiqlExpress({ 
    endpointURL: '/graphql' 
}));

app.use(
  '/graphql',
  bodyParser.json(),
  graphqlExpress( (req) => {
    console.log('/graphql User: ' + req.user); // prints undefined after sending correct login credentials to /login
    return ({
    schema,
    context: {
      user: req.user,
    },
  });}),
);

app.use(bodyParser.urlencoded({ extended: true }) );
app.post('/login', passport.authenticate('local'), (req, res) => {
  console.log('/login: User', req.user); // prints the logged in user's data
  return res.sendStatus(200);
});

export default app;

这是来自客户端的登录获取请求:

onSubmit = () => {

    var details = {
      'email': this.state.email,
      'password': this.state.password,
    };

    var formBody = [];
    for (var property in details) {
      var encodedKey = encodeURIComponent(property);
      var encodedValue = encodeURIComponent(details[property]);
      formBody.push(encodedKey + "=" + encodedValue);
    }
    formBody = formBody.join("&");

    fetch('http://localhost:3001/login', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'
      },
      credentials: 'include',
      body: formBody
    }).then(function(response) {
      console.log(response);
    }).catch(function(err) {
      // Error
    });
  };

我是否必须在客户端更改某些内容才能让服务器接收会话 cookie?还是后端出了什么问题?

我还向这个 repo 上传了一个最小示例:https://github.com/schmitzl/passport-graphql-minimal-example

【问题讨论】:

    标签: node.js reactjs passport.js graphql express-session


    【解决方案1】:

    在处理 CORS 时,管理会话会变得有些混乱。您需要进行一些更改才能获得您所期望的行为:

    首先,修改您的服务器代码以确保发送Access-Control-Allow-Credentials 标头:

    app.use('*', cors({ origin: 'http://localhost:3000', credentials: true }));
    

    接下来,确保您的请求实际上包含 cookie。通过将credentials 选项设置为include,您已经完成了登录请求。 Apollo 在后台使用 fetch,我们也需要将此选项传递给它。

    我可能遗漏了一些东西,但似乎apollo-boost 并没有提供一种简单的方法来执行上述操作(您有 fetchOptions,但包括credentials 似乎没有做任何事情)。我的建议是废弃apollo-boost,直接使用适当的库(或使用apollo-client-preset)。然后您可以将适当的credentials 选项传递给HttpLink

    import ApolloClient from 'apollo-client'
    import { HttpLink, InMemoryCache } from 'apollo-client-preset'
    
    const client = new ApolloClient({
      link: new HttpLink({ uri: apolloUri, credentials: 'include' }),
      cache: new InMemoryCache()
    })
    

    【讨论】:

    • 谢谢,问题解决了! cookie 现在已在 graphql 查询中正确设置,我可以访问用户对象。
    猜你喜欢
    • 2021-04-02
    • 2018-11-06
    • 1970-01-01
    • 2018-10-16
    • 2019-08-23
    • 2018-08-01
    • 2020-07-25
    • 2019-03-13
    • 2020-03-09
    相关资源
    最近更新 更多