NodeJS 了解passport序列化反序列化

tzcvj98z  于 2023-01-20  发布在  Node.js
关注(0)|答案(6)|浏览(204)

您如何向外行解释Passport的序列化和反序列化方法的工作流?
1.调用passport.serializeUser后,user.id将转到哪里?
1.我们在它之后调用passport.deserializeUser,它在工作流中的位置是什么?

// used to serialize the user for the session
passport.serializeUser(function(user, done) {
    done(null, user.id); 
   // where is this user.id going? Are we supposed to access this anywhere?
});

// used to deserialize the user
passport.deserializeUser(function(id, done) {
    User.findById(id, function(err, user) {
        done(err, user);
    });
});

我还在努力理解它。我有一个完整的工作应用程序,没有遇到任何错误。
我只想知道到底发生了什么?
任何帮助都很感激。

ss2ws0br

ss2ws0br1#

1.调用passport.serializeUser后,user.id将转到哪里?
用户id(作为done函数的第二个参数提供)保存在会话中,稍后用于通过deserializeUser函数检索整个对象。
serializeUser确定用户对象的哪些数据应该存储在会话中。serializeUser方法的结果作为req.session.passport.user = {}附加到会话。例如,在这里,它将是(因为我们提供用户id作为键)req.session.passport.user = {id: 'xyz'}
1.我们在它后面调用passport.deserializeUser,它在工作流中的位置是什么?
deserializeUser的第一个参数对应于done函数的用户对象的键(见1.)。因此,整个对象都是在该键的帮助下检索的。该键在这里是用户id(键可以是用户对象的任何键,如名称、电子邮件等)。在deserializeUser中,该键与内存数组/数据库或任何数据源匹配。
获取的对象作为req.user附加到请求对象

可视化流程

passport.serializeUser(function(user, done) {
    done(null, user.id);
});              │
                 │ 
                 │
                 └─────────────────┬──→ saved to session
                                   │    req.session.passport.user = {id: '..'}
                                   │
                                   ↓           
passport.deserializeUser(function(id, done) {
                   ┌───────────────┘
                   │
                   ↓ 
    User.findById(id, function(err, user) {
        done(err, user);
    });            └──────────────→ user object attaches to the request as req.user   
});
vaj7vani

vaj7vani2#

对于使用Koa和koa-passport的用户:
知道serializeUser方法中设置的用户密钥(通常是该用户的唯一ID)将存储在以下位置:
this.session.passport.user
当您在deserializeUser的done(null, user)中设置时,其中'user'是数据库中的某个用户对象:
this.req.userthis.passport.user
由于某种原因,当您在deserializeUser方法中调用done(null,user)时,this.user Koa上下文永远不会被设置。
因此,您可以在调用app.use(passport.session())后编写自己的中间件,将其放入this.user中,如下所示:

app.use(function * setUserInContext (next) {
  this.user = this.req.user
  yield next
})

如果你不清楚serializeUser和deserializeUser是如何工作的,可以在twitter上联系我。

sgtfey8w

sgtfey8w3#

Passport使用serializeUser函数将用户数据(在成功验证后)持久化到会话中。函数deserializeUser用于从会话中检索用户数据。
serializeUserdeserializeUser函数都检查传递给它们的第一个参数,如果它是function类型,serializeUserdeserializeUser什么也不做,而是将这些函数放在函数堆栈中,之后将调用这些函数(当传递的第一个参数不是function类型时)。

app.use(session({ secret: "cats" }));
app.use(passport.initialize());
app.use(passport.session());

使用中间件的顺序很重要,当一个新的授权请求开始时,查看会发生什么是很重要的:

  • 会话中间件创建会话(使用来自sessionStore的数据)。
  • passport.initialize_passport对象分配给请求对象,检查是否存在会话对象,如果会话对象存在,并且字段passport存在于其中(如果不存在,则创建一个),将该对象分配给_passport中的session字段。最后,它看起来如下所示:
req._passport.session = req.session['passport']

因此,session字段引用了对象,该对象被赋值给req.session.passport

  • passport.sessionreq._passport.session中查找user字段,如果找到一个,则将其传递给deserializeUser函数并调用它。deserializeUser函数将req._passport.session.user赋值给请求对象的user字段(如果在req._passport.session.user中找到一个)。这就是为什么,如果我们在serializeUser函数中这样设置用户对象:
passport.serializeUser(function(user, done) {
  done(null, JSON.strignify(user)); 
});

然后我们需要解析它,因为它在user字段中保存为JSON

passport.deserializeUser(function(id, done) {
   // parsed user object will be set to request object field `user`
   done(err, JSON.parse(user));
 });

所以,当你设置Passport时,deserializeUser函数第一次被调用,把你的回调放在_deserializers函数栈中。第二次,它将在passport.session中间件中被调用,把user字段分配给请求对象。这也会在分配user字段之前触发我们的回调(我们放在passport.deserializeUser()中)。
设置Passport时首先调用的serializeUser函数(类似于deserializeUser函数),但它将用于序列化用户对象以保存在会话中。第二次,它将在login/logIn (alias)方法中被调用,由Passport附加,并用于保存会话中的用户对象。serializeUser函数还检查_serializers堆栈是否具有已推送到其中的函数(其中一个是在设置Passport时添加的):

passport.serializeUser(function(user, done) ...

并调用它们,然后分配用户对象将用户ID(已删除)或用户ID更改为req._passport.session.user。请务必记住,session字段直接引用req.session对象中的passport字段。这样,用户在会话中保存了(因为req._passport.session引用了对象req.session.passportpassport.initialize中间件在每次传入请求时都会修改req._passport.session),当请求结束时,req.session数据将存储在sessionStore中。
成功授权后,当第二个请求开始时会发生什么:

  • session中间件从sessionStore获取会话,我们的用户数据已经保存在其中
  • passport.initialize检查是否存在会话,并将req.session.passport分配给req._passport.session
  • passport.session检查req._passport.session.user并将其反序列化。在此阶段(如果req._passport.session.user为真),我们将具有req.user,并且req.isAuthenticated()返回true
flmtquvp

flmtquvp4#

您可以使用此代码升级旧的序列化和反序列化,请访问此帖子获取新的解决方案。

passport.serializeUser(function(user, cb) {
          process.nextTick(function() {
            cb(null, { id: user.id, username: user.username });
          });
        });
        
        passport.deserializeUser(function(user, cb) {
          process.nextTick(function() {
            return cb(null, user);
          });
        });
wydwbb8l

wydwbb8l5#

基本上,我们只是使用serializer将用户ID存储在会话中,当我们需要用户模型示例时,我们使用该用户ID在数据库中搜索,这是使用deserializer完成的。
只要会话是活动的并且用户被认证,

req.session.passport.user

将始终对应于用户模型示例。
如果我们不将用户ID保存到会话中,并且如果存在任何重定向,我们将无法知道用户是否经过身份验证。
一旦用户被认证,将设置req.session.passport.user,因此所有将来的请求将知道用户已经被认证。
希望这样简化。

erhoui1w

erhoui1w6#

所以我在这上面停留了相当长的一段时间,所以我做了一个快速安装文件,这样就没有人再在这个垃圾上停留了

passportmgmt.js

const localStrategy = require('passport-local').Strategy;
const bcrypt = require('bcrypt');
const User = require('./db-schemas/models').UserModel;
/*^^^^^^^^^^^ delete above import and modify below definition as needed 
const mongoose = require('mongoose')
mongoose.connect("mongodb://localhost:27017/database_name");

const UserSchema = new mongoose.Schema({
    username: {
        type: String,
        required: true
    },
    password: {
        type: String,
        required: true
    },
    email: {
        type: String,
        required: true
    }
});
const UserModel = mongoose.model('collection_name', UserSchema);
^^^^^^^^^^^^^^^ Change UserModel to User */
const passport = require('passport');

function passportSetupUwU(app) {
    const cookieParser = require('cookie-parser');
    const session = require('express-session');
    const MongoDBStore = require('connect-mongodb-session')(session);

    app.use(cookieParser());
    app.set('trust proxy', 1);
    app.use(session({
    secret: "secret",
    resave: false,
    saveUninitialized: false,
    store: new MongoDBStore({
        uri: "mongodb://localhost:27017/database_name",
        collection: "collection_name"
    })
    }));

    // Passport.js
    app.use(passport.initialize());
    app.use(passport.session());
}

passport.serializeUser(function(user, cb) {
    console.log("serializing user uwu:" + JSON.stringify(user))
    process.nextTick(function() {
        return cb(null, user.id)
    })
})

passport.deserializeUser(function (id, cb) {
    console.log("deserializing user owo:" + JSON.stringify(id))
    User.findOne({id:id}, function (err, user) {
        if (err) { return cb(err)}
        return cb(null, user);
    })
});

passport.use(new localStrategy(function (username, password, done) {
    console.log("attempted login with %s:%s", username, password);
    User.findOne({ username: username }, function (err, user) {
        if (err) return done(err);
        if (!user) return done(null, false, { message: 'No such user exists.' });

        bcrypt.compare(password, user.password, function (err, res) {
            if (err) return done(err);
            if (res === false) return done(null, false, { message: 'Incorrect password.' });
            
            return done(null, user);
        });
    });
}));

module.exports = {setup: passportSetupUwU}

现在只需导入并运行app.js中的passportSetupUwU函数,即可开始:

应用程序js试验

// some example middleware and stuff i happened to have
const PPSetup = require('./passportmgmt').setup
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(express.static(path.join(__dirname, 'public')));

//
// <- PUT IT LIKE HERE OR SOMETHING
//
PPSetup(app);

// some example routes and api endpoints i happened to have
app.use('/api/', apiRouter);
apiRouter.use('/', indexRouter);
apiRouter.use('/users', usersRouter);

apiRouter.post('/login', passport.authenticate('local', {

相关问题