O que o middleware passport.session () faz?

125

Estou construindo um sistema de autenticação usando o Passport.js usando o Easy Node Authentication: Setup e o tutorial local .

Estou confuso sobre o que passport.session()faz.

Depois de brincar com o middleware diferente, cheguei a entender que express.session()é o que envia um ID de sessão através de cookies para o cliente, mas estou confuso sobre o que passport.session()faz e por que é necessário além disso express.session().

Aqui está como eu configuro meu aplicativo:

// Server.js configura o aplicativo e configura o servidor da web

//importing our modules
var express = require('express');
var app = express();
var port = process.env.PORT || 8080;
var mongoose = require('mongoose');
var passport = require('passport');
var flash = require('connect-flash');

var configDB = require('./config/database.js');

//Configuration of Databse and App

mongoose.connect(configDB.url); //connect to our database

require('./config/passport')(passport); //pass passport for configuration

app.configure(function() {

    //set up our express application

    app.use(express.logger('dev')); //log every request to the console
    app.use(express.cookieParser()); //read cookies (needed for auth)
    app.use(express.bodyParser()); //get info from html forms

    app.set('view engine', 'ejs'); //set up ejs for templating

    //configuration for passport
    app.use(express.session({ secret: 'olhosvermelhoseasenhaclassica', maxAge:null })); //session secret
    app.use(passport.initialize());
    app.use(passport.session()); //persistent login session
    app.use(flash()); //use connect-flash for flash messages stored in session

});

//Set up routes
require('./app/routes.js')(app, passport);

//launch
app.listen(port);
console.log("Server listening on port" + port);
Georges Krinker
fonte

Respostas:

139

passport.session() atua como um middleware para alterar o objeto req e alterar o valor 'user' que atualmente é o ID da sessão (do cookie do cliente) para o verdadeiro objeto de usuário desserializado.

Enquanto as outras respostas fazem alguns pontos positivos, pensei que poderiam ser fornecidos alguns detalhes mais específicos.

app.use(passport.session());

é equivalente a

app.use(passport.authenticate('session'));

Onde 'sessão' refere-se à seguinte estratégia que acompanha o passportJS.

https://github.com/jaredhanson/passport/blob/master/lib/strategies/session.js

Especificamente as linhas 59-60:

var property = req._passport.instance._userProperty || 'user';
req[property] = user;

Onde ele atua essencialmente como um middleware e altera o valor da propriedade 'user' no objeto req para conter a identidade desserializada do usuário. Para permitir que isso funcione corretamente, você deve incluir serializeUsere deserializeUserfunções no seu código personalizado.

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

passport.deserializeUser(function (user, done) {
    //If using Mongoose with MongoDB; if other you will need JS specific to that schema.
    User.findById(user.id, function (err, user) {
        done(err, user);
    });
});

Isso localizará o usuário correto do banco de dados e passará como uma variável de fechamento no retorno de chamada, done(err,user);para que o código acima passport.session()possa substituir o valor de 'usuário' no objeto req e passar para o próximo middleware na pilha.

lindsaymacvean
fonte
hey, como eu pode armazenar detalhes do usuário na sessão só eu não quero armazená-los em banco de dados dirctly
Newbiee
1
"nos cabeçalhos da solicitação"? não apenas na solicitação objeto
caub
Percebi que, se a estratégia da sessão puder restaurar a autenticação e desserializar o usuário. Mas, apesar disso, a autenticação ainda passa para a próxima estratégia, que é a autenticação do facebook no meu cenário. Gostaria de saber qual é o ponto da estratégia da sessão se ela ainda continuar a invocar as estratégias a seguir, mesmo quando a sessão puder recuperar o usuário.
Nishant 09/08/19
15

A partir da documentação

Em um aplicativo baseado no Connect ou Express, o middleware passport.initialize () é necessário para inicializar o Passport. Se seu aplicativo usar sessões de login persistentes, o middleware passport.session () também deverá ser usado.

e

Sessões

Em um aplicativo Web típico, as credenciais usadas para autenticar um usuário serão transmitidas apenas durante a solicitação de login. Se a autenticação for bem-sucedida, uma sessão será estabelecida e mantida por meio de um conjunto de cookies no navegador do usuário.

Cada solicitação subsequente não conterá credenciais, mas o cookie exclusivo que identifica a sessão. Para dar suporte às sessões de login, o Passport serializará e desserializará as instâncias do usuário para e da sessão.

e

Observe que ativar o suporte à sessão é totalmente opcional, embora seja recomendado para a maioria dos aplicativos. Se ativado, certifique-se de usar express.session () antes de passport.session () para garantir que a sessão de logon seja restaurada na ordem correta.

Josh C.
fonte
1
Obrigado pela sua resposta rápida, mas isso não responde à minha pergunta. Além disso, observe que, se você tiver um aplicativo expresso e usar express.session (), em qualquer cliente que se conectar ao seu servidor expresso (se ele está autenticado ou não), ele receberá uma sessão por meio de um cookie. Isso é independente de ele estar ou não em uma página protegida por login do seu aplicativo. Eu ainda gostaria de saber a diferença entre os dois middlewares.
Georges Krinker
1
@GeorgesKrinker são os métodos serializeUser () e deserializeUser. O middleware expresso restaurará as informações da sessão, mas isso não está necessariamente relacionado à forma como o passaporte está gerenciando as informações do usuário. Isso deve ser feito após a sessão ser reidratada por expresso.
27414 Josh
Bem, eu tive a impressão de que os métodos serializeUser () e deserializeUser eram executados em authenticate () dentro das rotas.
Georges Krinker
@GeorgesKrinker Acho que não. Quando usei o passaporte, chamei apenas .authenticate no login.
27413 Josh C.
app.post('/login', passport.authenticate('local'), ...
27414 Josh C.
11

Enquanto você estiver usando PassportJspara validar o usuário como parte do seu URL de login, você ainda precisa de algum mecanismo para armazenar essas informações do usuário na sessão e recuperá-las com cada solicitação subsequente (por exemplo, serializar / desserializar o usuário).

Portanto, na verdade, você está autenticando o usuário com todas as solicitações, mesmo que essa autenticação não precise procurar um banco de dados ou oauth como na resposta de login. Portanto, o passaporte tratará a autenticação de sessão também como mais uma estratégia de autenticação.

E para usar essa estratégia - chamada session, basta usar um atalho simples - app.use(passport.session()). Observe também que essa estratégia específica deseja que você implemente funções de serialização e desserialização por razões óbvias.

uniwalker
fonte
11

Simplesmente autentica a sessão (que é preenchida por express.session()). É equivalente a:

passport.authenticate('session');

como pode ser visto no código aqui:

https://github.com/jaredhanson/passport/blob/42ff63c/lib/authenticator.js#L233

Jared Hanson
fonte
6
O que você quer dizer? É executado em todas as solicitações e não necessariamente possui credenciais para autenticar. Você se importaria em me fornecer um pouco mais de detalhes sobre o fluxo de trabalho que ocorre em cada solicitação?
Georges Krinker 27/02
6
Sim, é executado em cada solicitação. O ID da sessão que é gerado pelo Express é um ID exclusivo que é aproximadamente equivalente a um token de autenticação que o navegador envia a cada solicitação. Os dados armazenados nesta sessão são usados ​​para restaurar o estado de autenticação do usuário.
Jared Hanson
Olá @JaredHanson Você pode dar uma olhada nisso . Não encontrei a resposta em lugar algum?
Saras Arya
@JaredHanson Estou tentando usar o passport.js para se autenticar com um servidor de autorização de código aberto amplamente usado e compatível com OAuth2. Mas estou recebendo um erro. Você está disposto a ajudar a resolver o problema? Aqui está o link: stackoverflow.com/questions/38176236/…
DollarCoffee
@JaredHanson: O que observo é que o objeto req aumentado com informações passport.user logo após o login via google-oauth é perdido quando a próxima solicitação de nova página é feita no site. Esse comportamento é esperado? Então, estou sem saber como recuperar as informações do usuário recém-conectado.
user1102171