Sequelize:不要return密码

Sequelize: don't return password

我正在使用 Sequelize 为用户记录进行数据库查找,我希望模型的默认行为为 not return password 该记录的字段。 password 字段是一个散列,但我仍然不想 return 它。

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

  1. User 模型创建自定义 class 方法 findWithoutPassword 并在该方法中使用 attributes 执行 User.find设置如图Sequelize docs

  2. 做一个正常的User.find并在控制器中过滤结果(不是首选)

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

有没有更好的方法?最好的是,如果有一种方法可以在 Sequelize 模型定义中指定从不 return password 字段,但我还没有找到一种方法来做到这一点。

我建议覆盖 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 克隆返回的对象 - 否则您将从实例中完全删除 属性。

scoping attributes as discussed here有一个插件。

我使用了已接受答案中提到的覆盖,除了我调用原始 toJSON 而不是 getthis.constructor.super_.prototype.toJSON.apply(this, arguments) api docs[ 中所述=15=]

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

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

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

阅读docs了解更多详情

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

在模型的选项对象中添加这个

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

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

在模型的选项对象中添加这个

scopes: {
  withoutPassword: {
    attributes: { exclude: ['password'] },
  }
}

然后就可以在查询中使用了

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

我喜欢结合使用 Pawan 的两个答案并声明如下:

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

这允许我在默认情况下排除密码并使用 withPassword 范围在需要时显式 return 密码,例如当 运行 登录方法时。

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

这确保在通过引用字段包含用户时不会 return 编辑密码,例如

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

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

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

我可以通过在 returns undefined

字段中添加 getter 来实现此功能
firstName: {
      type: DataTypes.STRING,
      get() {
        return undefined;
      }
    }

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

我有一个虚拟字段,比如 fullName,它取决于我想隐藏的字段,比如 firstNamelastName。而基于defaultScope在这种情况下不起作用。

您可以通过排除属性以一种简单的方式做到这一点。请参见下面的代码(注释行)

    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}`
        });
    });