我将 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 = '    ';
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;
这是我的passportConfig.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 });
});
}));
};
有谁知道这可能是什么原因造成的?