Node.Js + express + Passport:无法注销用户

时间:2021-11-21 12:31:17

I wrote a JS script for a webserver that includes authentication using the passport and the digest strategy. I am not using sessions, but I have tried using sessions and it does not change the results. The browser requests the "/login" route and displays a built-in login dialog. Authentication works fine, but I can't get the user to "logout." The problem seems to be that the browser remembers the login credentials and resends them automatically. The end result is that the user must close the browser completely to log out, but that is a problem for this application. I know that there must be a way to tell the browser not to do this, but I haven't figured it out.

我为网络服务器编写了一个JS脚本,其中包括使用护照和摘要策略进行身份验证。我没有使用会话,但我尝试使用会话,但它不会改变结果。浏览器请求“/ login”路由并显示内置登录对话框。身份验证工作正常,但我无法让用户“注销”。问题似乎是浏览器会记住登录凭据并自动重新发送。最终结果是用户必须完全关闭浏览器才能注销,但这对此应用程序来说是个问题。我知道必须有一种方法告诉浏览器不要这样做,但我还没弄明白。

I figured out a hack to get the browser to display the login dialog again; force the authentication function to return a false. However, I haven't figured out a way to do this per-session. Right now, if one person logs out, everyone gets logged out. It's not a workable solution.

我想出了一个让浏览器再次显示登录对话框的黑客攻击;强制验证功能返回false。但是,我还没有找到一种方法来执行每个会话。现在,如果一个人退出,每个人都会退出。这不是一个可行的解决方案。

Can anyone tell me what I'm doing wrong here? One thing I'm wondering is whether I'm returning the proper response to the browser when it POSTs to the /logout route (see end). I return res.json(""), but maybe there's a different response I should send to tell the browser to forget the credentials for the session?

谁能告诉我这里我做错了什么?我想知道的一件事是,当它发布到/ logout路由时,我是否正在向浏览器返回正确的响应(参见结束)。我返回res.json(“”),但是我应该发送一个不同的响应来告诉浏览器忘记会话的凭据?

My code follows. Any insight is greatly appreciated. Thank you in advance.

我的代码如下。非常感谢任何见解。先谢谢你。

T

var passport = require('passport'), 
    DigestStrategy = require('passport-http').DigestStrategy;

var express = require('express');
var app = express();
app.configure(function () {
    app.use(
        "/", //the URL throught which you want to access to you static content
        express.static('./www') //where your static content is located in your filesystem
    );
  app.use(express.cookieParser());
  app.use(express.bodyParser());
  app.use(express.session({ secret: 'keep moving forward' }));
  app.use(passport.initialize());
  app.use(passport.session());
  app.use(app.router);


});
app.listen(80); //the port you want to use


/**
 * CORS support.
 */

app.all('*', function(req, res, next){
  if (!req.get('Origin')) return next();
  // use "*" here to accept any origin
  // For specific domain, do similar: http://localhost'
  // Use an array for multiple domains, like [http://localhost', 'http://example.com' ]
  res.set('Access-Control-Allow-Origin', '*' );
  res.set('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
  res.set('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type, Authorization');
  next();
});


//
// Configure passport authentication
//


// Used to force the browser to display the login screen again.
var forceLogin = false;
passport.use(new DigestStrategy({ qop: 'auth' },
  function(username, done ) { 

  if ( !forceLogin )
  {
    return done(null, username, "nimda");
  }
  else
  {
    //
    // Forces the browser to request the user name again by returning a failure to its last request.
    //
    console.log ( "forcing user to log in"  );
    forceLogin = false;
    return done(null, false);
  }
));

passport.serializeUser(function(user, done) {

    console.log( "serialize user " + user.toString() );
    done(null, user.toString());
});

passport.deserializeUser(function(id, done) {
    console.log( "deserialize user " + id.toString() );
    done(null, id);
});

app.post('/login', passport.authenticate('digest', { session: true }),
  function(req, res) {
    console.log( "/login");
    res.header('Cache-Control', 'no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0');
    res.json({ id: req.user.id, username: req.user.username });
 }); 

app.post('/logout', function(req, res){

  req.logOut();

  // NOTE: Same results as req.logout
  //
  //  req.session.destroy(function (err) {
  //   res.redirect('/'); 
  //  });

  res.redirect("/");

  // flag to force a login
  forceLogin = true;

  console.log( "logout");

  // Is this the proper return to the browser?
  return res.json("");
});

4 个解决方案

#1


6  

You could try the following

您可以尝试以下方法

req.session.destroy()
req.logout()
res.redirect('/')

Saving the new state of the session is important if you're using some form a session store for persistent sessions (eg. Redis). I tried the above code with a similar setup and it seems to work for me

如果您使用某种形式的会话存储来执行持久会话(例如Redis),则保存会话的新状态非常重要。我用类似的设置尝试了上面的代码,它似乎对我有用

#2


4  

Server needs somehow notify web browser that he need to refresh login info (MD5 digests). For that you can send 401 error code and usually browser will show login popup message.

服务器需要以某种方式通知Web浏览器他需要刷新登录信息(MD5摘要)。为此,您可以发送401错误代码,通常浏览器将显示登录弹出消息。

By the way, all these tricks with sessions are useless because browser already have all required info for automatic logging in.

顺便说一句,所有这些带有会话的技巧都是无用的,因为浏览器已经拥有自动登录所需的所有信息。

So you can try next code:

所以你可以尝试下一个代码:

req.logout();
res.send("logged out", 401);

#3


4  

A bit late to the party, but I found this thread on Google while searching for answer and nothing worked for me. Finally, I was able to solve it so thought I could post solution here for anyone that might read this in the future.

派对有点晚了,但我在搜索答案时在Google上发现了这个帖子,对我来说没什么用。最后,我能够解决它,以为我可以在这里发布解决方案给任何可能在将来阅读此内容的人。


So basically, I use node.js, express, passport(local) and rethinkdb as my storage, and I was having problem with req.logout(); not logging me out.

所以基本上,我使用node.js,express,passport(local)和rethinkdb作为我的存储,我遇到了req.logout();没有让我退出

My setup:

var express = require( 'express' );
var passport = require( 'passport' );
var session = require( 'express-session' );
var RDBStore = require( 'express-session-rethinkdb' )( session );

I tried a lot of stuff and nothing was working, so finally I decided to manually do it, by removing session record from database myself.

我尝试了很多东西,没有任何工作,所以最后我决定手动执行它,通过自己从数据库中删除会话记录。

Here is the code I used: app.get( '/logout', function ( req, res, next ) {

这是我使用的代码:app.get('/ logout',function(req,res,next){

    if ( req.isUnauthenticated() ) {

        // you are not even logged in, wtf
        res.redirect( '/' );

        return;

    }

    var sessionCookie = req.cookies['connect.sid'];

    if ( ! sessionCookie ) {

        // nothing to do here
        res.redirect( '/' );

        return;

    }

    var sessionId = sessionCookie.split( '.' )[0].replace( 's:', '' );

    thinky.r.db( 'test' ).table( 'session' ).get( sessionId ).delete().run().then( function( result ) {

        if ( ! result.deleted ) {

            // we did not manage to find session for this user
            res.redirect( '/' );

            return;

        }

        req.logout();
        res.redirect( '/' );

        return;

    });

});

So I hope this helps someone :)

所以我希望这有助于某人:)

#4


0  

res.redirect('/') will end the response, you can not call subsequently write(), end(), send(), json() ...etc

res.redirect('/')将结束响应,你不能随后调用write(),end(),send(),json()......等

Just like this:

像这样:

app.post('/logout', function(req, res){
  req.logOut();
  res.redirect("/");
});

deserializeUser should return a user instead of id:

deserializeUser应返回用户而不是id:

passport.deserializeUser(function(id, done) {
    findUser(id, function(err, user) {
       if(err) {
          done(err)
       } else {
          done(null, user);
       }
    }
});

I have taken a short discussion, I realize that digest username/password store on browser (not on server), so req.logout not help, there no way to clear it from server. You just close browser and open again that mean logout.

我做了一个简短的讨论,我意识到浏览器上的摘要用户名/密码存储(不在服务器上),所以req.logout没有帮助,没有办法从服务器清除它。您只需关闭浏览器并再次打开即表示注销。

You can use a variable in cookie or session to mark the session as logout, but I think we should not do not, because username/password still in browser.

您可以在cookie或会话中使用变量将会话标记为注销,但我认为我们不应该这样做,因为用户名/密码仍然在浏览器中。

It's digest!

#1


6  

You could try the following

您可以尝试以下方法

req.session.destroy()
req.logout()
res.redirect('/')

Saving the new state of the session is important if you're using some form a session store for persistent sessions (eg. Redis). I tried the above code with a similar setup and it seems to work for me

如果您使用某种形式的会话存储来执行持久会话(例如Redis),则保存会话的新状态非常重要。我用类似的设置尝试了上面的代码,它似乎对我有用

#2


4  

Server needs somehow notify web browser that he need to refresh login info (MD5 digests). For that you can send 401 error code and usually browser will show login popup message.

服务器需要以某种方式通知Web浏览器他需要刷新登录信息(MD5摘要)。为此,您可以发送401错误代码,通常浏览器将显示登录弹出消息。

By the way, all these tricks with sessions are useless because browser already have all required info for automatic logging in.

顺便说一句,所有这些带有会话的技巧都是无用的,因为浏览器已经拥有自动登录所需的所有信息。

So you can try next code:

所以你可以尝试下一个代码:

req.logout();
res.send("logged out", 401);

#3


4  

A bit late to the party, but I found this thread on Google while searching for answer and nothing worked for me. Finally, I was able to solve it so thought I could post solution here for anyone that might read this in the future.

派对有点晚了,但我在搜索答案时在Google上发现了这个帖子,对我来说没什么用。最后,我能够解决它,以为我可以在这里发布解决方案给任何可能在将来阅读此内容的人。


So basically, I use node.js, express, passport(local) and rethinkdb as my storage, and I was having problem with req.logout(); not logging me out.

所以基本上,我使用node.js,express,passport(local)和rethinkdb作为我的存储,我遇到了req.logout();没有让我退出

My setup:

var express = require( 'express' );
var passport = require( 'passport' );
var session = require( 'express-session' );
var RDBStore = require( 'express-session-rethinkdb' )( session );

I tried a lot of stuff and nothing was working, so finally I decided to manually do it, by removing session record from database myself.

我尝试了很多东西,没有任何工作,所以最后我决定手动执行它,通过自己从数据库中删除会话记录。

Here is the code I used: app.get( '/logout', function ( req, res, next ) {

这是我使用的代码:app.get('/ logout',function(req,res,next){

    if ( req.isUnauthenticated() ) {

        // you are not even logged in, wtf
        res.redirect( '/' );

        return;

    }

    var sessionCookie = req.cookies['connect.sid'];

    if ( ! sessionCookie ) {

        // nothing to do here
        res.redirect( '/' );

        return;

    }

    var sessionId = sessionCookie.split( '.' )[0].replace( 's:', '' );

    thinky.r.db( 'test' ).table( 'session' ).get( sessionId ).delete().run().then( function( result ) {

        if ( ! result.deleted ) {

            // we did not manage to find session for this user
            res.redirect( '/' );

            return;

        }

        req.logout();
        res.redirect( '/' );

        return;

    });

});

So I hope this helps someone :)

所以我希望这有助于某人:)

#4


0  

res.redirect('/') will end the response, you can not call subsequently write(), end(), send(), json() ...etc

res.redirect('/')将结束响应,你不能随后调用write(),end(),send(),json()......等

Just like this:

像这样:

app.post('/logout', function(req, res){
  req.logOut();
  res.redirect("/");
});

deserializeUser should return a user instead of id:

deserializeUser应返回用户而不是id:

passport.deserializeUser(function(id, done) {
    findUser(id, function(err, user) {
       if(err) {
          done(err)
       } else {
          done(null, user);
       }
    }
});

I have taken a short discussion, I realize that digest username/password store on browser (not on server), so req.logout not help, there no way to clear it from server. You just close browser and open again that mean logout.

我做了一个简短的讨论,我意识到浏览器上的摘要用户名/密码存储(不在服务器上),所以req.logout没有帮助,没有办法从服务器清除它。您只需关闭浏览器并再次打开即表示注销。

You can use a variable in cookie or session to mark the session as logout, but I think we should not do not, because username/password still in browser.

您可以在cookie或会话中使用变量将会话标记为注销,但我认为我们不应该这样做,因为用户名/密码仍然在浏览器中。

It's digest!