首页 > 解决方案 > Passport.js:LocalStrategy 如何访问用户信息?

问题描述

我已经阅读了几篇文章,解释了护照身份验证的流程并理解了大部分概念。但是,仍有一些模糊的地方需要解释,以便我可以一劳永逸地了解 Passport。
让我们看看这个实现用户注册的简单示例:

护照.js

passport.use(
  'register',
  new LocalStrategy(
    {
      usernameField: 'username',
      passwordField: 'password',
      passReqToCallback: true,
      session: false,
    },
    (req, username, password, done) => {
      // TODO:Why is req.body.email is used and not req.body.username
      // And how are these values passed to register in the first place?
      console.log(username);
      console.log(req.body.email);

      try {
        User.findOne({
          where: {
            [Op.or]: [
              {
                username,
              },
              { email: req.body.email },
            ],
          },
        }).then(user => {
          if (user != null) {
            console.log('username or email already taken');
            return done(null, false, {
              message: 'username or email already taken',
            });
          }
          /**
           * on register the user’s password is hashed and salted with the encryption package bcrypt
           * 
           */
          bcrypt.hash(password, BCRYPT_SALT_ROUNDS).then(hashedPassword => {
            User.create({
              username,
              password: hashedPassword,
              email: req.body.email,
            }).then(user => {
              console.log('user created');
              return done(null, user);
            });
          });
        });
      } catch (err) {
        //In case of an Error interacting with our database, we need to invoke done(err)
        //Calling done will make the flow jump back into passport.authenticate. 
        //It's passed the error, user and additional info object (if defined).
        return done(err);
      }
    },
  ),
);

注册用户.js:

app.post('/registerUser', (req, res, next) => {
    //Calling done will make the flow jump back into passport.authenticate. 
    //It's passed the error, user and additional info object (if defined).

    passport.authenticate('register', (err, user, info) => {
      if (err) {
        console.error(err);
      }
      if (info !== undefined) {
        console.error(info.message);
        res.status(403).send(info.message);
      } else {
        // eslint-disable-next-line no-unused-vars
        req.logIn(user, error => {
          console.log(user);
          const data = {
            first_name: req.body.first_name,
            last_name: req.body.last_name,
            email: req.body.email,
            username: user.username,
          };
          console.log(data);
          User.findOne({
            where: {
              username: data.username,
            },
          }).then(user => {
            console.log(user);
            user
              .update({
                first_name: data.first_name,
                last_name: data.last_name,
                email: data.email,
              })
              .then(() => {
                console.log('user created in db');
                res.status(200).send({ message: 'user created' });
              });
          });
        });
      }
    })(req, res, next);
  });

问题 1:知道已以这种方式调用 Passport.authenticate ,我看不到LocalStrategy内部的代码如何访问用户信息:

    app.post('/registerUser', (req, res, next) => {
passport.authenticate('register', (err, user, info) => {

那么 **regiser LocalStrategy ** 中的代码如何访问用户名、电子邮件和密码:

(req, username, password, done) => {
  console.log(username);
  console.log(req.body.email);  

问题2:为什么LocalStrategy中的用户名直接称为用户名 (密码相同)而电子邮件由req.body.email调用

 console.log(username);
  console.log(req.body.email); 

和这里:

User.create({
              username,
              password: hashedPassword,
              email: req.body.email,
            })

问题3:如果注册LocalStrategy中已经创建了用户,为什么还要在请求回调中更新用户信息:

注册用户.js

  .update({
                first_name: data.first_name,
                last_name: data.last_name,
                email: data.email,
              })

护照.js

User.create({
              username,
              password: hashedPassword,
              email: req.body.email,
            })

编辑 1
问题 4:(req, res, next) 的作用是什么;在POST回调结束时?

标签: javascriptnode.jsauthenticationpassport.js

解决方案


问题 1&2:答案在传递的对象中LocalStrategy

   {
      usernameField: 'username',
      passwordField: 'password',
      passReqToCallback: true,
      session: false,
    }  

属性passReqToCallbackreq将作为第一个参数传递给验证回调:

(req, username, password, done) => {}  

但是,仍然不清楚的是用户名和密码是如何传递给这个函数的。为什么在这个对象中以这种方式定义它们:

 usernameField: 'username',
 passwordField: 'password', 

不应该像电子邮件一样通过 req.body.username 访问它们:

User.findOne({
          where: {
            [Op.or]: [
              {
                username,
              },
              { email: req.body.email },
            ],
          },   

问题3:这是我找到的解释:

我也可以将这些额外的数据传递给中间件,但我希望 Passport 只处理身份验证,而不是用户创建。模块化,记住。

另外,如果将身份验证拆分为一个单独的服务,其中包含一个仅包含加密用户名和密码的单独数据库,那么这样做会更容易,然后使用用户名或 ID 来查找和更新此文件中的相应用户记录注册服务。


推荐阅读