如果应用程序在Express JS服务器的2个选项卡中运行,则在第一个选项卡中的会话被销毁后如何重定向到第二个选项卡中的主页

问题描述

我已经创建了一个基本的登录页面,成功登录后,用户将被重定向到成功页面。 在成功页面中,它们是一个标签,该标签通过get request重定向到/ logout并破坏会话并重定向到homepage。我的问题是,如果用户打开了该应用程序的2个实例并从一个选项卡注销,则另一个instanace(tab)正常工作,直到刷新页面,然后显示禁止”。所以我该怎么做才能从两个选项卡中注销,就像facebook或amazon一样,这里是代码

const express = require('express');
const url= require('url');
const db=require('./dao.js');
var bodyParser = require('body-parser')
const session = require("express-session");
const app= express();
const nunjucks=require("nunjucks");
const path = require('path');
const Pin=require('./models/pin');
const User=require('./models/users');
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
app.use(bodyParser.urlencoded({ extended: false }));

app.use(express.static(path.resolve(__dirname,'public')));
nunjucks.configure(path.resolve(__dirname,'views'),{
    express:app,autoscape:true,noCache:false,watch:true
}); 
app.use(session({
    secret: "session",resave: false,saveUninitialized: true,cookie: { secure: false }
  }));
  
//passoprt consfig
app.use(passport.initialize());
app.use(passport.session());
passport.serializeUser(function (user,done) {
    done(null,user.id);
  });
  passport.deserializeUser(function (user,next) {
    next(null,user);
  });

  

passport.use('local',new LocalStrategy((username,password,done) => {
  
    User.findOne({ username: username },(err,user) => { 
      if (err) { return done(err); }
      if (!user) { return done(null,null,{ message: 'No user found!' }); }
      if (user.password !== password) {
        return done(null,{ message: 'Username or password is incorrect!' });
      }
  
      return done(null,user,null);
    });
  }
  ));
  function isAuthenticated(req,res,next) {
    if (req.isAuthenticated()) {
      next();
    } else {
        req.session.destroy();
      res.status(403).send('Forbidden');
    }
  }  
   
 

app.get("/",(req,res)=>{
    console.log("hi"); 
    res.render("validate.html",{});
    });
    app.post('/login',res) => {
        // passport.authenticate('local',{ successRedirect: '/admin',failureRedirect: '/login' }
        passport.authenticate('local',function (err,info) {
          //  console.log(err,info);
          if (err) {
            res.render('validate.html',{ error: err });
          } else if (!user) {
            res.render('validate.html',{ errorMessage: info.message });
      
          } else {
            //setting users in session
            req.logIn(user,function (err) { 
              if (err) {
                res.render('/',{ error: err });
              } else {
                res.redirect('/success');
              }
            })
          }
        })(req,res);
      });
      
app.get('/success',isAuthenticated,res)=>{
    res.render("index.html",{});
})
app.get("/logout",function (req,res) {
    req.session.destroy();
    res.redirect('/');
});

app.get("/pincode",res)=>{
    console.log(req.query.pincode);
    let pin=req.query.pincode;
    let pattern= /^[0-9]*$/;
    
if(pattern.test(pin)){
    Pin.find({pincode:pin},data)=>{
        if(err)
        {
            console.log("error");
        }
        else
        {
            console.log(data);
            //res.render('index.html',{data:data}); 
            res.status(200).send(data);
            //res.status(200).json(data);
        }
    });
}
else{
   res.status(200).send("Nan");
   //res.render('index.html',{nomessage:"Not a no"}); 
                            
} 
    
    // res.redirect('http://google.com');
   
});
app.listen(80,()=>{
    console.log("App running at port 80");
});
<!doctype html>
<html lang="en">
  <head>
    <!-- required Meta tags -->
    <Meta charset="utf-8">
    <Meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no">

    <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.14.0/css/all.min.css" integrity="sha512-1PKOgIY59xJ8Co8+NE6FZ+LOAZKjy+KY8iq0G4B3CyeY6wYHN3yt9PW0XpSriVlkmxe40PTknxrLnZ9+fkDaog==" crossorigin="anonymous" />
    <link rel="stylesheet" href="css/style.css">
    <title>Hello,world!</title>
  </head>
  <body>
      <div class="div1">
        <div class="container-sm">
            <div class="row">
                <form action="/login" method="POST" class="col-12" id=form autocomplete="off">
                  <p class="text-danger">{{message}}</p>
                  <p class="text-danger">{{error}}</p>
                  <p class="text-danger">{{errorMessage}}</p>

                    <input type="text" name="username" id="pin" placeholder="enter email" >
                    <input type="password" name="password" placeholder="enter passowrd">
                    <button type="submit" id=btn>login</button>
                  
                </form>
                
            </div>
            

        </div>
    </div>
        
    
    <!-- Optional JavaScript -->
    <!-- jQuery first,then Popper.js,then Bootstrap JS -->
    <script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js" integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" 

<!-- begin snippet: js hide: false console: true babel: false -->

解决方法

此博客可能会有所帮助,

https://hasura.io/blog/best-practices-of-using-jwt-with-graphql/

基于博客

如果我登录不同的选项卡会怎样?

解决此问题的一种方法是通过在localstorage上引入全局事件侦听器。每当我们在一个选项卡上的localstorage中更新此注销键时,侦听器都会在其他选项卡上触发并触发“注销”,并将用户重定向到登录屏幕。

window.addEventListener('storage',this.syncLogout) 

//....


syncLogout (event) {
  if (event.key === 'logout') {
    console.log('logged out from storage!')
    Router.push('/login')
  }
}

这些是我们现在注销时需要做的两件事:

取消令牌 在本地存储中设置注销项目

async function logout () {
  inMemoryToken = null;
  const url = 'http://localhost:3010/auth/logout'
  const response = await fetch(url,{
    method: 'POST',credentials: 'include',})
  // to support logging out from all windows
  window.localStorage.setItem('logout',Date.now())
}
view rawlogout2.js hosted with ❤ by GitHub

在这种情况下,只要您从一个标签页中注销,事件监听器就会在所有其他标签页中触发,并将它们重定向到登录屏幕。