MERN Passport在每个请求上反序列化两次

时间:2018-07-04 23:09:06

标签: node.js mongodb express passport.js mern

我正在将mern.io与Passport和Express-Sessions一起用于我的应用程序。对于每个请求,针对同一请求两次调用deserializeUser。这与express.static或express.favicon无关,其他用户指出这可能是罪魁祸首。第一次被调用为req.user是未定义的。第二次调用它时,req.user是正确的。在两种情况下,deserializeUser中的userObject都是正确的:

{ userId: '1234',
  firstName: 'Joe',
  lastName: 'Smith',
  email: 'asdf@aol.com' }

这是我的server.js:

import Express from 'express';
import compression from 'compression';
import bodyParser from 'body-parser';
import path from 'path';
const passport = require('passport');
const cookieParser = require('cookie-parser');
const expressSession = require('express-session');
const MongoStore = require('connect-mongo')(expressSession);

// Webpack Requirements
import webpack from 'webpack';
import config from '../webpack.config.dev';
import webpackDevMiddleware from 'webpack-dev-middleware';
import webpackHotMiddleware from 'webpack-hot-middleware';

// Initialize the Express App
const app = new Express();

// Set Development modes checks
const isDevMode = process.env.NODE_ENV === 'development' || false;
const isProdMode = process.env.NODE_ENV === 'production' || false;

// Run Webpack dev server in development mode
if (isDevMode) {
  const compiler = webpack(config);
  app.use(webpackDevMiddleware(compiler, { noInfo: true, publicPath: 
config.output.publicPath }));
  app.use(webpackHotMiddleware(compiler));
}

// React And Redux Setup
import { configureStore } from '../client/store';
import { Provider } from 'react-redux';
import React from 'react';
import { renderToString } from 'react-dom/server';
import { match, RouterContext } from 'react-router';
import Helmet from 'react-helmet';

import routes from '../client/routes';
import { fetchComponentData } from './util/fetchData';
import serverConfig from './config';
import serverRoutes from './routes/routes';

app.use(compression());
app.use(Express.static(path.resolve(__dirname, '../dist/client')));
app.use(cookieParser('somethingsomething'));
app.use(bodyParser.json({ limit: '20mb' }));
app.use(bodyParser.urlencoded({ limit: '20mb', extended: false }));

require('./passportConfig')(passport);
app.use(expressSession({
  name: 'testApp',
  secret: 'somethingsomething',
  resave: true,
  saveUninitialized: false,
  store: new MongoStore({ url: process.env.DBURL }),
  cookie: {
    maxAge: 36000 * 24 * 14,
    secure: false,
  },
}));
app.use(passport.initialize());
app.use(passport.session());
app.use((req, res, next) => {
  res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
  next();
});

app.use('/api', serverRoutes);


// Render Initial HTML
const renderFullPage = (html, initialState) => {
  const head = Helmet.rewind();

// Import Manifests
const assetsManifest = process.env.webpackAssets && JSON.parse(process.env.webpackAssets);
const chunkManifest = process.env.webpackChunkAssets && JSON.parse(process.env.webpackChunkAssets);

  return `
    <!doctype html>
    <html>
      <head>
        ${head.base.toString()}
        ${head.title.toString()}
        ${head.meta.toString()}
        ${head.link.toString()}
        ${head.script.toString()}

        ${isProdMode ? `<link rel='stylesheet' href='${assetsManifest['/app.css']}' />` : ''}
        <link href='https://fonts.googleapis.com/css?family=Lato:400,300,700' rel='stylesheet' type='text/css'/>
        <link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.2.12/semantic.min.css"></link>
        <link rel="shortcut icon" href="http://res.cloudinary.com/hashnode/image/upload/v1455629445/static_imgs/mern/mern-favicon-circle-fill.png" type="image/png" />
      </head>
      <body>
        <div id="root"><div>${html}</div></div>
        <script>
          window.__INITIAL_STATE__ = ${JSON.stringify(initialState)};
          ${isProdMode ?
          `//<![CDATA[
          window.webpackManifest = ${JSON.stringify(chunkManifest)};
          //]]>` : ''}
        </script>
        <script src='${isProdMode ? assetsManifest['/vendor.js'] : '/vendor.js'}'></script>
        <script src='${isProdMode ? assetsManifest['/app.js'] : '/app.js'}'></script>
      </body>
    </html>
  `;
};

const renderError = err => {
  const softTab = '&#32;&#32;&#32;&#32;';
  const errTrace = isProdMode ?
    `:<br><br><pre style="color:red">${softTab}${err.stack.replace(/\n/g, `<br>${softTab}`)}</pre>` : '';
  return renderFullPage(`Server Error${errTrace}`, {});
};

// Server Side Rendering based on routes matched by React-router.
    app.use((req, res, next) => {
  match({ routes, location: req.url }, (err, redirectLocation, renderProps) => {
    if (err) {
      return res.status(500).end(renderError(err));
    }

    if (redirectLocation) {
      return res.redirect(302, redirectLocation.pathname + redirectLocation.search);
    }

    if (!renderProps) {
      return next();
    }

    const store = configureStore();

    return fetchComponentData(store, renderProps.components, renderProps.params)
      .then(() => {
        const initialView = renderToString(
          <Provider store={store}>
            <RouterContext {...renderProps} />
          </Provider>
        );
        const finalState = store.getState();

        res
          .set('Content-Type', 'text/html')
          .status(200)
          .end(renderFullPage(initialView, finalState));
      })
      .catch((error) => next(error));
  });
});

// start app
app.listen(serverConfig.port, (error) => {
  if (!error) {
    console.log(`MERN is running on port: ${serverConfig.port}! Build something amazing!`); // eslint-disable-line
  }
});

export default app;

这是我的passwordConfig.js:

const LocalStrategy = require('passport-local').Strategy;
const request = require('request');
const apiUrl = process.env.API_URL;
const token = process.env.TOKEN;
const User = require('./models/user');
import Config from './config';

const API_URL = (typeof window === 'undefined' || process.env.NODE_ENV === 'test') ?
  process.env.BASE_URL || (`http://localhost:${process.env.PORT || Config.port}/api`) : '/api';

module.exports = (passport) => {
  passport.serializeUser((userObject, done) => {
    done(null, userObject);
  });

  passport.deserializeUser((userObject, done) => {
    if (userObject.adminUser) done(null, userObject.adminUser);
    else done(null, userObject);
  });

  passport.use('local-login', new LocalStrategy({
    usernameField: 'email',
    passwordField: 'password',
    passReqToCallback: true, // allows us to pass back the entire request to the callback
  }, (req, email, password, done) => {
  const proj = {
    firstName: 1,
    lastName: 1,
    email: 1,
  };
  User.findOneAsync({ email }, proj)
  .then(user => {
    const userData = {
      userId: user._id,
      firstName: user.firstName,
      lastName: user.lastName,
      email: user.email,
    };
    return done(null, userData);
  });
})
);

passport.use('signUp', new LocalStrategy({
  usernameField: 'email',
  passwordField: 'password',
  passReqToCallback: true,
}, (req, email, password, done) => {
  request({
    url: `${API_URL}/signIn`,
    method: 'POST',
    json: {
      email,
      password,
    },
    'Content-Type': 'application/json',
    Accept: 'application/json',
    headers: {
    Authorization: token,
    },
  }, (err, resp, body) => {
    const respBody = body || {};
    if (err) return done(err);

    if (!respBody.email) return done(null, false, { message: respBody.err });

    return done(null, { user: respBody });
  });
}));
};

有人知道这是什么原因吗?

0 个答案:

没有答案