2013-04-12 3 views
5

Ich benutze this example gefunden auf Github für Passport lokale Strategie mit Mungo/Mongodb. Das Problem, auf das ich stoße, ist, dass Benutzer, die sich abmelden, immer noch auf eingeschränkte Informationen zugreifen können, indem sie die Zurück-Taste im Browser drücken. Ich bin ein wenig neu bei node.js, aber ich würde mir vorstellen, dass irgendeine Art von Hook implementiert werden müsste, um die ensureAuthenticated Funktion aufzurufen, die sich ganz unten im Code befindet, bevor die Schaltflächen Zurück und Vorwärts ausgeführt werden . Wie kann ich verhindern, dass ein Benutzer auf eingeschränkte Informationen zugreift, indem er auf die Zurück-Schaltfläche klickt, nachdem sich der Benutzer abgemeldet hat?Wie kann ich verhindern, dass die Zurück-Taste des Browsers auf eingeschränkte Informationen zugreift, nachdem sich der Benutzer abgemeldet hat?

var express = require('express') 
    , passport = require('passport') 
    , LocalStrategy = require('passport-local').Strategy 
    , mongodb = require('mongodb') 
    , mongoose = require('mongoose') 
    , bcrypt = require('bcrypt') 
    , SALT_WORK_FACTOR = 10; 

mongoose.connect('localhost', 'test'); 
var db = mongoose.connection; 
db.on('error', console.error.bind(console, 'connection error:')); 
db.once('open', function callback() { 
    console.log('Connected to DB'); 
}); 

// User Schema 
var userSchema = mongoose.Schema({ 
    username: { type: String, required: true, unique: true }, 
    email: { type: String, required: true, unique: true }, 
    password: { type: String, required: true}, 
    accessToken: { type: String } // Used for Remember Me 
}); 

// Bcrypt middleware 
userSchema.pre('save', function(next) { 
    var user = this; 

    if(!user.isModified('password')) return next(); 

    bcrypt.genSalt(SALT_WORK_FACTOR, function(err, salt) { 
     if(err) return next(err); 

     bcrypt.hash(user.password, salt, function(err, hash) { 
      if(err) return next(err); 
      user.password = hash; 
      next(); 
     }); 
    }); 
}); 

// Password verification 
userSchema.methods.comparePassword = function(candidatePassword, cb) { 
    bcrypt.compare(candidatePassword, this.password, function(err, isMatch) { 
     if(err) return cb(err); 
     cb(null, isMatch); 
    }); 
}; 

// Remember Me implementation helper method 
userSchema.methods.generateRandomToken = function() { 
    var user = this, 
     chars = "_!abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890", 
     token = new Date().getTime() + '_'; 
    for (var x = 0; x < 16; x++) { 
    var i = Math.floor(Math.random() * 62); 
    token += chars.charAt(i); 
    } 
    return token; 
}; 

// Seed a user 
var User = mongoose.model('User', userSchema); 
// var usr = new User({ username: 'bob', email: '[email protected]', password: 'secret' }); 
// usr.save(function(err) { 
// if(err) { 
//  console.log(err); 
// } else { 
//  console.log('user: ' + usr.username + " saved."); 
// } 
// }); 


// Passport session setup. 
// To support persistent login sessions, Passport needs to be able to 
// serialize users into and deserialize users out of the session. Typically, 
// this will be as simple as storing the user ID when serializing, and finding 
// the user by ID when deserializing. 
// 
// Both serializer and deserializer edited for Remember Me functionality 
passport.serializeUser(function(user, done) { 
    var createAccessToken = function() { 
    var token = user.generateRandomToken(); 
    User.findOne({ accessToken: token }, function (err, existingUser) { 
     if (err) { return done(err); } 
     if (existingUser) { 
     createAccessToken(); // Run the function again - the token has to be unique! 
     } else { 
     user.set('accessToken', token); 
     user.save(function (err) { 
      if (err) return done(err); 
      return done(null, user.get('accessToken')); 
     }) 
     } 
    }); 
    }; 

    if (user._id) { 
    createAccessToken(); 
    } 
}); 

passport.deserializeUser(function(token, done) { 
    User.findOne({accessToken: token } , function (err, user) { 
    done(err, user); 
    }); 
}); 


// Use the LocalStrategy within Passport. 
// Strategies in passport require a `verify` function, which accept 
// credentials (in this case, a username and password), and invoke a callback 
// with a user object. In the real world, this would query a database; 
// however, in this example we are using a baked-in set of users. 
passport.use(new LocalStrategy(function(username, password, done) { 
    User.findOne({ username: username }, function(err, user) { 
    if (err) { return done(err); } 
    if (!user) { return done(null, false, { message: 'Unknown user ' + username }); } 
    user.comparePassword(password, function(err, isMatch) { 
     if (err) return done(err); 
     if(isMatch) { 
     return done(null, user); 
     } else { 
     return done(null, false, { message: 'Invalid password' }); 
     } 
    }); 
    }); 
})); 


var app = express(); 

// configure Express 
app.configure(function() { 
    app.set('views', __dirname + '/views'); 
    app.set('view engine', 'ejs'); 
    app.engine('ejs', require('ejs-locals')); 
    app.use(express.logger()); 
    app.use(express.cookieParser()); 
    app.use(express.bodyParser()); 
    app.use(express.methodOverride()); 
    app.use(express.session({ secret: 'keyboard cat' })); // CHANGE THIS SECRET! 
    // Remember Me middleware 
    app.use(function (req, res, next) { 
    if (req.method == 'POST' && req.url == '/login') { 
     if (req.body.rememberme) { 
     req.session.cookie.maxAge = 2592000000; // 30*24*60*60*1000 Rememeber 'me' for 30 days 
     } else { 
     req.session.cookie.expires = false; 
     } 
    } 
    next(); 
    }); 
    // Initialize Passport! Also use passport.session() middleware, to support 
    // persistent login sessions (recommended). 
    app.use(passport.initialize()); 
    app.use(passport.session()); 
    app.use(app.router); 
    app.use(express.static(__dirname + '/../../public')); 
}); 
app.get('/users', function(req, res) { 
    var users = User.find(); 
    console.log(users); 
    res.send(users); 
}); 

app.get('/', function(req, res){ 
    res.render('index', { user: req.user }); 
}); 

app.get('/account', ensureAuthenticated, function(req, res){ 
    res.render('account', { user: req.user }); 
}); 

app.get('/login', function(req, res){ 
    res.render('login', { user: req.user, message: req.session.messages }); 
}); 

// POST /login 
// Use passport.authenticate() as route middleware to authenticate the 
// request. If authentication fails, the user will be redirected back to the 
// login page. Otherwise, the primary route function function will be called, 
// which, in this example, will redirect the user to the home page. 
// 
// curl -v -d "username=bob&password=secret" http://127.0.0.1:3000/login 
// 
/***** This version has a problem with flash messages 
app.post('/login', 
    passport.authenticate('local', { failureRedirect: '/login', failureFlash: true }), 
    function(req, res) { 
    res.redirect('/'); 
    }); 
*/ 

// POST /login 
// This is an alternative implementation that uses a custom callback to 
// acheive the same functionality. 
app.post('/login', function(req, res, next) { 
    passport.authenticate('local', function(err, user, info) { 
    if (err) { return next(err) } 
    if (!user) { 
     req.session.messages = [info.message]; 
     return res.redirect('/login') 
    } 
    req.logIn(user, function(err) { 
     if (err) { return next(err); } 
     return res.redirect('/'); 
    }); 
    })(req, res, next); 
}); 

app.get('/logout', function(req, res){ 
    req.logout(); 
    res.redirect('/'); 
}); 

app.listen(3000, function() { 
    console.log('Express server listening on port 3000'); 
}); 


// Simple route middleware to ensure user is authenticated. 
// Use this route middleware on any resource that needs to be protected. If 
// the request is authenticated (typically via a persistent login session), 
// the request will proceed. Otherwise, the user will be redirected to the 
// login page. 
function ensureAuthenticated(req, res, next) { 
    if (req.isAuthenticated()) { return next(); } 
    res.redirect('/login') 
} 

bearbeiten
ich glaube, ich auf etwas sein könnte, aber es funktioniert nicht bekommen kann. Nach weiteren Recherchen, Es scheint, dass ich das lokale Caching verhindern muss. Ich versuche, dies zu tun aus meiner app.configure Funktion:

app.configure(function() { 
    app.use(function(req, res, next) { 
    res.header('Cache-Control', 'no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0'); 
    next(); 
    }); 
}); 

Dies ist jedoch nicht meine Header zu sein scheint zu bewirken.

Antwort

0

Wenn der Benutzer im Browser zurück navigiert, werden die Daten aus dem Cache des lokalen Browsers angezeigt und nicht von Ihrem Server angefordert. Was Sie tun können, ist, Ihrem Logout-Event etwas Javascript hinzuzufügen. Dieser Teil von js kann vertrauliche Seiten aus dem Browserverlauf entfernen. Sie können mit window.history arbeiten, um den Browserverlauf zu manipulieren. Werfen Sie einen Blick in this guide for manipulating the browser history und die window.history api.

Nicht sicher, ob dies kugelsicher ist.

2

Da der Browser diese Seite aus dem Cache zieht, ist es egal, Sie tun auf dieser Seite, es sei denn, Sie fügen eine JS-Überprüfung, um zu sehen, ob der Benutzer noch authentifiziert ist ... aber das löst nicht Das Problem, dass die Seite im Cache ist.

das Problem als Cache Reframing ein, fand ich diese Antwort: https://stackoverflow.com/a/24591864/217374

Es ist schon über ein Jahr her, seit Sie gefragt, so dass ich nicht erwarten, dass Sie speziell die Antwort mehr, brauchen aber es ist für jeden anderen, der vorbeikommt.

0

Fügen Sie diese Zeilen in Ihrem HTML (oder Dateien anzeigen)

meta(http-equiv='Cache-Control', content='no-store, no-cache, must-revalidate') 
meta(http-equiv='Pragma', content='no-cache') 
meta(http-equiv='Expires', content='-1')