你如何向外行解释Passport的序列化和反序列化方法的工作流程?

Where does user.id go after passport.serializeUser has been called? We are calling passport.deserializeUser right after it where does it fit in the workflow? // 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); }); });

我还没想明白呢。我有一个完整的工作应用程序,没有遇到任何类型的错误。

我只是想知道这里到底发生了什么?

任何帮助都是感激的。


当前回答

基本上,我们只是使用序列化器将user-id存储在会话中,当我们需要用户模型实例时,我们使用user-id在数据库中搜索,这是使用反序列化器完成的。

只要会话是活动的,并且用户通过了身份验证,

req.session.passport.user

将始终对应于用户模型实例。

如果我们不将user-id保存到会话中,如果有重定向,我们将无法知道用户是否已经过身份验证。

一旦用户通过身份验证,就会设置req.session.passport.user。 因此,所有未来的请求都将知道用户已经过身份验证。

希望这能简化。

其他回答

所以我在这个问题上卡住了很长一段时间,所以我做了一个快速的设置文件,这样就不会有人再被这个垃圾卡住了

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函数,你就可以开始了:

app.js exerpt

// 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', {

对于任何使用可可豆和可可豆护照的人:

要知道serializeUser方法中设置的用户的键(通常是该用户的唯一id)将存储在:

this.session.passport.user

当你在deserializeUser中设置done(null, user)时,其中“user”是数据库中的某个用户对象:

this.req.user 或 this.passport.user

出于某种原因。在您的deserializeUser方法中调用done(null, user)时,用户Koa上下文永远不会被设置。

所以你可以在调用app.use(passport.session())之后编写自己的中间件,把它放在这里。用户如下:

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

如果您不清楚serializeUser和deserializeUser是如何工作的,请在twitter上联系我。@yvanscher

用户在哪里。我去拿护照。serializeUser是否被调用?

用户id(作为done函数的第二个参数提供)保存在会话中,稍后用于通过deserializeUser函数检索整个对象。

serializeUser决定会话中应该存储用户对象的哪些数据。serializeUser方法的结果作为req.session.passport.user ={}附加到会话。例如,在这里,它将是(因为我们提供用户id作为键)req.session.passport.user = {id: 'xyz'}

我们在它后面调用passport。deserializeuser它在工作流中的位置是什么?

deserializeUser的第一个参数对应给done函数的user对象的键(见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   
});

Passport的序列化和反序列化方法的可视化工作流:

User logs in to your application and provides their credentials. Passport uses the serializeUser function to take the user object and convert it into a session object. Passport stores the session object on the server and sends a session cookie to the user's browser. 4.User makes a request to your application. 5.Passport uses the deserializeUser function to take the session object and convert it back into a user object. Passport passes the user object to your application, which can then use it to determine if the user is authenticated or not. If the user is authenticated, your application will allow them to access the requested resource. If the user is not authenticated, your application will deny access and redirect them to the login page.

下面是工作流的可视化表示:

    +------------+             +---------------+
|            |             |               |
| User Login |             | Session Object |
|            |    serializeUser    |               |
+-----+------+   ------------------>   +---------+
      |                                 |           |
      |                                 | Store on  |
      |                                 | Server    |
      |                                 |           |
+-----+------+   <------------------   +---------+
|            |             |               |
| User Request |    deserializeUser    |               |
|            |   ------------------>   |             |
+------------+             |               +-----------+
      |                   |
      |                   |
      |                   |
+-----+------+   <------------------   +---------+
|            |             |               |
| Authenticated |             |     User     |
|  or not       |             |             |
|            |             |               |
+------------+             +---------------+

我希望这有助于阐明Passport的序列化和反序列化方法的工作流程!

基本上,我们只是使用序列化器将user-id存储在会话中,当我们需要用户模型实例时,我们使用user-id在数据库中搜索,这是使用反序列化器完成的。

只要会话是活动的,并且用户通过了身份验证,

req.session.passport.user

将始终对应于用户模型实例。

如果我们不将user-id保存到会话中,如果有重定向,我们将无法知道用户是否已经过身份验证。

一旦用户通过身份验证,就会设置req.session.passport.user。 因此,所有未来的请求都将知道用户已经过身份验证。

希望这能简化。