节点+ Express +护照:需求用户未定义


74

我的问题是类似这样的一个,但没有深入了解他的解决方案。

我正在使用Passport通过Instagram进行身份验证。成功通过身份验证后,用户将被定向到“ /”。在这一点上,请求具有用户对象(也可以正常工作)。但是,一旦我重定向,req.user是未定义的。:'(

奇怪的是,每个请求都会调用passport.deserializeUser。它成功获取了用户对象,但是在中间件的某个地方,未设置(或未设置)req.user。

// on successful auth, goto "/" 
app.get('/', function(req, res) {
    // if the request has the user object, go to the user page
    if (req.user) {
        res.redirect("/user/" + req.user._id);
    }

    res.render("index");
}

app.get('/user/:uid', function(req, res) {
    console.log(req.user) // undefined
}

3
您可以发布应用程序的配置吗?app.use(...)特别是中间件()。可能是您的会话Cookie的有效期限太低,或者您的中间件顺序错误。
罗伯特克莱普

中间件订购很可能是这里的问题
诺亚,

1
我完全按照中间件在Passport配置页中的说明进行操作,并且仍然面临相同的问题
vsync

1
您找到解决方案了吗?
草莓2013年

1
我有同样的问题。我无法正常工作,似乎req.user每次都重置了-Gang
Su

Answers:


46

您是否为应用设置了会话状态?你需要这样的东西...

app.use(session({ secret: 'anything' }));
app.use(passport.initialize());
app.use(passport.session());

22
我完全按照您的意思写了,我也收到了undefined 信息。
vsync

3
认为这实际上是app.use(session({secret : 'anything'});现在,快递会议是其自己的一揽子计划,而不是快递的一部分
加兹

2
设置表达式后,我仍然遇到问题。初始化Express-Session后,我正在调用通行证功能,我可以在应用程序中顺利使用会话。
Pietro Coelho 2015年

passport.session()如果我不使用会话,是否需要@martin ?
Zlatko

2
从我的应用程序配置顺序错误的角度来看,此解决方案对我有用。当我按上面的顺序放置它们时,问题已解决。
fraxture '16

57

我的问题不是在客户端上使用获取时指定发送cookie。在请求中包含凭据:“ include”字段后,它起作用了。

fetch('/api/foo', {credentials: 'include'})

8
花了太多时间寻找解决方案,尝试以各种方式在服务器端配置通行证,只是发现问题出在客户端代码中。感谢您的回答。
Anurag Awasthi,2017年

4
等等,如何更容易找到这个技巧?找到这个之前,我阅读了很多StackOverflow问题和答案。谢谢乔恩·罗德尼斯。谢谢。
tscizzle

花了4个小时,又节省了我大约一天的时间,也可能是一个月。:P
Thirunavukkarasu Muthuswamy

1
稍微扩展一下,只有在请求来自相同来源的情况下,才默认发送cookie之类的东西。否则,您必须使用该withCredentials标志来指定您实际上确实希望将cookie发送回去。请参阅developer.mozilla.org/zh-CN/docs/Web/API/Request/credentials。请注意,如果您使用的是Axios之类的东西而不是fetch API,则语法会有所不同。
亚当·泽纳

17

我对Node非常陌生,但这对我来说是一个中间件问题。添加了bodyParser并进行了重新排列以进行修复。

损坏的代码:

app.use(express.cookieParser('secret'));
app.use(express.cookieSession());
app.use(express.session({ secret: 'anything' }));
app.use(passport.initialize());
app.use(passport.session());
app.use(app.router);
app.use(express.static(path.join(__dirname, 'public'))); 

工作代码:

app.use(express.static(path.join(__dirname, 'public')));
app.use(express.cookieParser());
app.use(express.bodyParser());
app.use(express.session({ secret: 'anything' }));
app.use(passport.initialize());
app.use(passport.session());
app.use(app.router);

希望这可以帮助


这对我有帮助。为什么中间件的第二顺序而不是第一顺序工作?
宋卓

尝试以各种方式调试事物的时间浪费了很多时间,最终归结为这一点。其express.static作为最后中间件的一个对我来说破有关的一切权威性。它甚至不是一致的行为,有时它起作用,有时却没有。我怀疑express /提到的libs代码中的某些内容非常粗略,容易出现竞争状况。
Vee6

12

以前我有以下代码(没有用):

app.use(express.static(path.join(__dirname, 'public')));
app.use(cookieParser('abcdefg'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
app.use(session({
    secret: 'abcdefg',
    resave: true,
    saveUninitialized: false,
    cookie: { secure: true } // this line
}));
app.use(passport.initialize());
app.use(passport.session());
app.use(require('stylus').middleware(path.join(__dirname, 'public')));

然后,我从会话初始化程序中删除cookie选项:

app.use(express.static(path.join(__dirname, 'public')));
app.use(cookieParser('abcdefg'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
app.use(session({
    secret: 'abcdefg',
    resave: true,
    saveUninitialized: false
}));
app.use(passport.initialize());
app.use(passport.session());
app.use(require('stylus').middleware(path.join(__dirname, 'public')));

现在可以了。


1
@Squirrl他的快速服务器可能位于终止SSL连接的代理(Heroku,nginx,IISnode)的后面。那很正常 在这里阅读有关详细说明:stackoverflow.com/questions/33871133/…
克里斯蒂安韦斯特比克

5

我遇到了同样的问题,因为仅复制并粘贴了Express-Session文档中的以下代码,而没有完全阅读文档。

app.use(session({
  secret: 'keyboard cat',
  resave: false,
  saveUninitialized: true,
  cookie: { secure: true }
}))

在文档中,它提到:

但是,它需要启用HTTPS的网站,即HTTPS对于安全cookie是必需的。如果设置了安全性,并且您通过HTTP访问站点,则不会设置cookie。

因此,如果您只有HTTP连接,请删除安全选项,以下代码应该可以工作:

app.use(session({
  secret: 'keyboard cat',
  resave: false,
  saveUninitialized: true,
  //cookie: { secure: true } remove this line for HTTP connection
}))

谢谢!我花了两个小时拼命地做这件事,才意识到几个月前我已经将cookie升级到HTTPS,并且正在通过HTTP在本地进行测试。
miguelmorin

4

我在使用Express 4时遇到了完全相同的问题,并且尝试了几乎所有可以在网上找到的东西之后,我终于设法通过添加“ cookie-session”使其开始工作。

var cookieSession = require('cookie-session');

app.use(cookieSession({
  keys: ['key1', 'key2']
}));

4

是的,启用@Martin之类的会话。但是,如果您使用的是Express 4. *版本,则不会捆绑会话之类的中间件,因此您需要单独安装它。

  1. 添加“ express-session”:“ 1.4.0”在package.json中
  2. npm安装
  3. 用它

;

var express = require('express');
var cookieParser = require('cookie-parser')
var session = require('express-session')
var app = express()
app.use(cookieParser()) // required before session.
app.use(session({secret: 'keyboard cat'}))

有关更多信息,请参阅快速会议文档。


根据链接到的文档,不再建议使用Cookie Parser。
对抗

3

在路线中,尝试添加: {session: true}

app.get('/auto-login', passport.authenticate('cross', {session: true}))

1
花了大约一个小时调试护照的内部结构,才得出相同的结论。 req.user如果您session: false在的呼叫选项中指定,则不会设置passport.authenticate
埃文·西洛基

{ session: true }似乎是默认设置。
Flaudre '16

奇怪的是,这也对我有用。护照v0.3.2。
hyubs

1
我正在使用,passport-twitter并且明确设置会话对我不起作用。在同一应用中,passport-google-auth执行完全相同的代码行是可以的。
老盖泽尔

3

对用户进行身份验证时,将req.user填充请求值。要知道是否标识用户并填写该值,将使用cookie。如果像我一样,您使用安全的cookie配置会话,则cookie仅在上可用HTTPS,这不是本地开发服务器的标准配置。要处理Cookie HTTP,注释掉cookie: { secure: true }req.user正确配置值:

this.app.use(session({
    resave: true,
    saveUninitialized: true,
    secret: process.env.SESSION_SECRET || "a secret",
    // cookie: { secure: true },
}));

如果合理地,您只想HTTPS在生产中使用cookie ,则可以执行以下操作:

cookie: { secure: process.env.ENV === 'PRODUCTION' }

2
非常感谢!患了一段时间。
Mathyou

谢谢!我花了两个小时拼命地做这件事,才意识到几个月前我已经将cookie升级到HTTPS,并且正在通过HTTP在本地进行测试。
miguelmorin

3

我认为每个人在服务器端都有一些错误,可能会导致此问题。

要解决此错误,请检查以下内容:

检查1-护照序列化和反序列化

正确的方法(猫鼬):

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

passport.deserializeUser((_id, done) => {
  User.findById( _id, (err, user) => {
    if(err){
        done(null, false, {error:err});
    } else {
        done(null, user);
    }
  });
});

检查2-会话

检查您的cookie会话程序包是否已正确配置并且可以正常工作。检查您是否真的可以在客户端看到cookie。如果您使用快速会话请确保您可以在内存或缓存(Redis)中看到session-id。

检查3-SSL Nginx

确保反向代理支持cookie和请求类型。不要忘记检查cookie /会话配置[secure标志]

遇到此错误时,我正在使用(user)回调函数。然后我用纠正了(err, user)。现在没事了。干杯🍻


1
谢谢!我花了两个小时拼命地做这件事,才意识到几个月前我已经将cookie升级到HTTPS,并且正在通过HTTP在本地进行测试。
miguelmorin

1

我的是关于饼干和玉米。我通过向服务器添加以下代码来解决:

allowCrossDomain = function(req, res, next) {
res.header('Access-Control-Allow-Origin', 'http://localhost:3000'); // your website
res.header('Access-Control-Allow-Credentials', 'true');
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, Content-Length, X-Requested-With');
if ('OPTIONS' === req.method) {
    res.send(200);
} else {
    next();
}};

1

完成快速会话设置后,请确保在生成req.user时使用的反序列化功能中对护照进行了序列化和反序列化。见说明这里从另一个计算器的问题。

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


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

1

当您在客户端使用http请求时,请记住附加凭据。在Angular2中,您需要添加选项参数:{withCredentials:true}。此后,您将具有相同的req.sessionID,直到再次重置它。

this._http.get("endpoint/something", { withCredentials: true })

1

我的与所有这些都不一样。我以前在本地WordPress站点上开发,然后切换到单独的Node / React项目。

由于两个项目都在localhost上运行,因此来自Wordpress站点的cookie仍然存在并正在发送。这是造成问题的原因。

我必须清除本地主机的cookie,然后它才能工作。


0

如果您的中间件堆栈不清楚,假设您在某处有会话中间件,则可以在重定向之前保存会话:

if (req.user) {
    req.session.save(function (err) {
        if (err) {
            // ... panic!
        }
        res.redirect("/user/" + req.user._id);
    });
    return;
}

0

您是否尝试在cookieParser中插入您的secretKey?

var passport = require('passport');
var expressSession = require('express-session');

app.use(express.static(path.join(__dirname, 'public')));
app.use(cookieParser('mySecretKey'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(expressSession({
secret: 'mySecretKey',
  resave: false,
  saveUninitialized: true
}));
app.use(passport.initialize());
app.use(passport.session());

0

有完全一样的问题。对我来说,解决方案是使用“客户端会话”而不是“ express-session”。

不起作用的代码:

var session = require('express-session');

app.use(bodyParser.urlencoded({ extended: false }));
app.use(express.static(path.join(__dirname, 'public')));
app.use(cookieParser());
app.use(bodyParser.json());
app.use(session({
    secret: 'random string',
    resave: true,
    saveUninitialized: true,
    cookie: { secure: true }
}));

工作代码:

var session = require('client-sessions');

        app.use(bodyParser.urlencoded({ extended: false }));
        app.use(express.static(path.join(__dirname, 'public')));
        app.use(cookieParser());
        app.use(bodyParser.json());
        app.use(session({
        cookieName: 'session',
        secret: 'random string',
        duration: 30 * 60 * 1000,
        activeDuration: 5 * 60 * 1000,
    }));

0

我在req.isAuthenticated()和req.user中都遇到了相同的问题,这是我如何解决的

  • req.isAuthenticated()通过在deserialize()内的findById()方法中用find()替换findOne()来解决,然后我可以保存经过身份验证的req,否则它什么也不返回。

  • 通过调整顺序解决req.user,首先应存储Express-Session,然后初始化通行证,然后将下一个会话存储在password.session()中,然后在将通行证保存在password.session()之后,我们可以访问req.user

app.use(session(...));
app.use(passport.initialize());
app.use(passport.session());
// Now we can access req.user so after we will call req.user, if we write it above these, it will always return underfined
app.use(function(req, res, next){
  res.locals.user = req.user || null
  next();
})

请参阅,如果您之后要访问req.user passport.session(),请在下面添加路由。


0

这样做时,passport.authenticate您可以添加session: true解决您的问题:

app.post("/login", passport.authenticate('local', {
    'failureRedirect': '/login',
    'session': true
}), (req, res)=>{ res.redirect("/"); });

0

我的两分钱:无法正常工作的代码:

server.use(
session({
  secret: "secretsssss",
  rolling: false,
  resave: false,
  saveUninitialized: false,
  cookie: {
    sameSite: true, //this line
    maxAge: 60 * 60 * 1000
  }
})
);

工作代码:

server.use(
session({
  secret: "secretsssss",
  rolling: false,
  resave: false,
  saveUninitialized: false,
  cookie: {
    sameSite: false, // i think this is default to false
    maxAge: 60 * 60 * 1000
  }
})
);

0

服务器发送SetCookie标头,然后通过浏览器句柄存储它,然后将Cookie与对Cookie HTTP标头内的同一服务器的请求一起发送。

我必须在客户中设置withCredentials:true。(axios.js)

const config = {
  withCredentials: true,
  headers: {
    'Content-Type': 'application/json',
  },
};

axios.put(url, { page: '123' }, config)
  .then(res => console.log('axios', res))
  .catch(err => console.log('axios', err));

然后发生CORS问题。

所以我将其添加到我的快递服务器中:

app.use(function(req, res, next) {
  res.header('Access-Control-Allow-Credentials', true);
  res.header('Access-Control-Allow-Origin', req.headers.origin);
  res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
  res.header('Access-Control-Allow-Headers', 'X-Requested-With, X-HTTP-Method-Override, Content-Type, Accept');
  if ('OPTIONS' == req.method) {
    res.send(200);
  } else {
      next();
  }
});

0

遇到同样的问题,但是我的误解更多与对OAuth流和OAuth回调路由之间passport.authorize以及passport.authenticate开始时的区别的误解有关。

passport.authorize不会影响该req.user变量,但是由于我只是复制并粘贴了该策略文档中的示例代码,因此我没有意识到使用了错误的方法。更改为passport.authenticate用户变量后可用。

希望这对任何可能在不知不觉中做同样事情的人有所帮助。


0

从此更改顺序:

app.set("view engine", "ejs");
app.use(bodyParser.urlencoded({ extended: true }));

对此:

app.use(bodyParser.urlencoded({ extended: true }));
app.set("view engine", "ejs");

欢迎使用堆栈溢出。不鼓励在堆栈溢出上使用仅代码的答案,因为它们没有解释它如何解决问题。请编辑您的答案以解释此更改如何解决问题中的问题,以便它对于遇到相同问题的其他用户也很有用。
FluffyKitten

0

我在将cookie解析器与express-session一起使用时是这样的:

var express = require("express"); // 4.16.1
var cors = require("cors"); // 2.8.5
var cookieParser = require("cookie-parser"); // 1.4.4
var expressSession = require("express-session"); // 1.17.1

var app = express();

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

app.use(express.json());
app.use(express.urlencoded({ extended: true }));


app.use(
  expressSession({
    secret: "secret123",
    resave: true,
    saveUninitialized: true,
    cookie: { maxAge: 60 * 60 * 24 * 1000 },
  })
);
app.use(cookieParser("secret123")); // this line

将cookie解析器放在express-session之前对我有用,像这样:

var express = require("express"); // 4.16.1
var cors = require("cors"); // 2.8.5
var cookieParser = require("cookie-parser"); // 1.4.4
var expressSession = require("express-session"); // 1.17.1

var app = express();

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

app.use(express.json());
app.use(express.urlencoded({ extended: true }));

app.use(cookieParser("secret123"));
app.use(
  expressSession({
    secret: "secret123",
    resave: true,
    saveUninitialized: true,
    cookie: { maxAge: 60 * 60 * 24 * 1000 },
  })
);

-1

我有一个不同的问题,与bcrpt-node和arrow函数有关。

起作用的代码:

userSchema.methods.generateHash = function (password) {
  return bcrypt.hashSync(password, bcrypt.genSaltSync(8), null); 
};

userSchema.methods.isValidPassword = function (password) {
  return bcrypt.compareSync(password, this.password);
};

无效的代码:

userSchema.methods.generateHash = (password) => {
  return bcrypt.hashSync(password, bcrypt.genSaltSync(8), null);
};

userSchema.methods.isValidPassword = (password) => {
  return bcrypt.compareSync(password, this.password);
};
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.