Sequelize:不要返回密码

时间:2015-01-15 20:19:21

标签: sequelize.js password-storage

我使用Sequelize为用户记录执行数据库查找,我希望模型的默认行为返回该记录的password字段。 password字段是哈希,但我仍然不想退回。

我有几个选项可行,但似乎没有一个特别好:

  1. findWithoutPassword模型创建自定义类方法User,并在该方法中执行User.find设置attributes,如{{3}所示}}

  2. 执行正常User.find并过滤控制器中的结果(不是首选)

  3. 使用其他库删除不需要的属性

  4. 有更好的方法吗?最重要的是,如果有一种方法可以在Sequelize模型定义中指定永远不会返回password字段,但我还没有找到方法来做到这一点。

8 个答案:

答案 0 :(得分:56)

我建议覆盖toJSON函数:

sequelize.define('user', attributes, {
  instanceMethods: {
    toJSON: function () {
      var values = Object.assign({}, this.get());

      delete values.password;
      return values;
    }
  }
});

或者在sequelize v4中

const User = sequelize.define('user', attributes, {});

User.prototype.toJSON =  function () {
  var values = Object.assign({}, this.get());

  delete values.password;
  return values;
}
将数据返回给用户时会调用

toJSON,因此最终用户无法看到密码字段,但仍会在您的代码中显示。

Object.assign克隆返回的对象 - 否则您将从实例中完全删除该属性。

答案 1 :(得分:39)

另一种方法是向用户模型添加默认范围。

在模型的选项对象

中添加它
defaultScope: {
  attributes: { exclude: ['password'] },
}

或者您可以创建单独的范围,仅在某些查询中使用它。

在模型的选项对象

中添加它
scopes: {
  withoutPassword: {
    attributes: { exclude: ['password'] },
  }
}

然后你可以在查询中使用它

User.scope('withoutPassword').findAll();

答案 2 :(得分:23)

也许您可以在exclude时在属性中添加find,如下所示:

var User = sequelize.define('user', attributes);

User.findAll({
    attributes: {
        exclude: ['password']
    }
});

阅读docs了解更多详情

答案 3 :(得分:9)

我喜欢结合使用Pawan的两个答案,并声明以下内容:

defaultScope: {
    attributes: { exclude: ['password'] },
},
scopes: {
    withPassword: {
        attributes: { },
    }
}

这使我默认情况下可以排除密码,并使用withPassword范围在需要时(例如在运行登录方法时)显式返回密码。

userModel.scope('withPassword').findAll()

这样可以确保在通过引用字段(例如,

)包含用户时不返回密码。

accountModel.findAll({
    include: [{
        model: userModel,
        as: 'user'
    }]
})

答案 4 :(得分:0)

已经讨论了scoping attributes here的插件。

我接受了接受回答中提到的覆盖,除了api docs toJSON而不是get this.constructor.super_.prototype.toJSON.apply(this, arguments) >

答案 5 :(得分:0)

以下代码对我有用。我们希望在运行时访问实例属性,但在将数据发送到客户端之前将其删除。

const Sequelize = require('sequelize')

const sequelize = new Sequelize('postgres://user:pass@example.com:5432/dbname')

const PROTECTED_ATTRIBUTES = ['password', 'token']

const Model = Sequelize.Model

class User extends Model {
  toJSON () {
    // hide protected fields
    let attributes = Object.assign({}, this.get())
    for (let a of PROTECTED_ATTRIBUTES) {
      delete attributes[a]
    }
    return attributes
  }
}

User.init({
  email: {
    type: Sequelize.STRING,
    unique: true,
    allowNull: false,
    validate: {
      isEmail: true
    }
  },
  password: {
    type: Sequelize.STRING,
    allowNull: false
  },
  token: {
    type: Sequelize.STRING(16),
    unique: true,
    allowNull: false
  },
},
{
  sequelize,
  modelName: 'user'
})

module.exports = User

Github Gist

答案 6 :(得分:0)

我可以通过在返回undefined的字段中添加一个吸气剂来解决这个问题。

firstName: {
      type: DataTypes.STRING,
      get() {
        return undefined;
      }
    }

当模型包含在另一个模型中时,accepted answer不起作用。

我有一个虚拟字段,例如fullName,它取决于我要隐藏的字段,例如firstNamelastName。并且基于defaultScope的{​​{3}}在这种情况下不起作用。

答案 7 :(得分:0)

您可以通过排除属性以简单的方式执行此操作。参见下面的代码(注释行)

    Patient.findByPk(id, {
            attributes: {
              exclude: ['UserId', 'DiseaseId'] // Removing UserId and DiseaseId from Patient response data
            },
            include: [
              { 
                model: models.Disease
              },
              {
                model: models.User,
                attributes: {
                  exclude: ['password'] // Removing password from User response data
                }
              }
           ]
    })
    .then(data => {
        res.status(200).send(data);
    })
    .catch(err => {
        res.status(500).send({
            message: `Error retrieving Patient with id ${id} : ${err}`
        });
    });