Sequelize:不要返回密码

Tyl*_*ler 25 password-storage sequelize.js

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

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

  1. 创建一个自定义的类方法findWithoutPasswordUser模型和方法中做了User.findattributes集如图所示Sequelize文档

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

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

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

Jan*_*ier 57

我建议覆盖toJSON函数:

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

      delete values.password;
      return values;
    }
  }
});
Run Code Online (Sandbox Code Playgroud)

或者在sequelize v4中

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

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

  delete values.password;
  return values;
}
Run Code Online (Sandbox Code Playgroud)

toJSON 在将数据返回给用户时调用,因此最终用户将看不到密码字段,但它仍将在您的代码中可用.

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

  • 重要!如果按照上面的说法操作,`delete values.password`实际上将从用户实例*中删除密码属性* - 而不仅仅是JSON输出.使用`var values = Object.assign({},this.get())`或适当的polyfill来避免改变实际用户的属性. (6认同)
  • 在这种情况下,您无法执行此操作-我们使用`.bind`来设置实例的上下文-但是您无法使用箭头功能执行此操作 (2认同)
  • 如果您只是创建用户的JSON表示形式,这将起作用。但!如果您包含来自另一个模型的用户,则被调用的`toJSON`就是其他模型!急于加载用户的密码时,这将导致您泄露哈希密码。看到这个:https://github.com/sequelize/sequelize/issues/3891 (2认同)

Paw*_*ani 52

另一种方法是向User模型添加默认范围.

在模型的选项对象中添加它

defaultScope: {
  attributes: { exclude: ['password'] },
}
Run Code Online (Sandbox Code Playgroud)

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

在模型的选项对象中添加它

scopes: {
  withoutPassword: {
    attributes: { exclude: ['password'] },
  }
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以在查询中使用它

User.scope('withoutPassword').findAll();
Run Code Online (Sandbox Code Playgroud)

  • 重要!这是唯一对我有用的答案.重要的是要知道,如果直接获取用户模型,接受的anwser将会起作用.如果您包含用户模型,则用户模型中的另一个模型toJSON功能将不会被调用,您将密码泄露给客户端! (4认同)
  • 这是最好的答案。我不知道为什么它不在顶部。 (2认同)
  • 注意:此答案工作正常,但排除的字段仍会为“创建”公开。覆盖 `toJSON` 可以保护字段在创建过程中不被暴露。 (2认同)

Lai*_*290 24

也许你可以exclude在你的属性中添加find,看起来像这样:

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

User.findAll({
    attributes: {
        exclude: ['password']
    }
});
Run Code Online (Sandbox Code Playgroud)

阅读文档了解更多详情

  • 在每个查询中添加`attributes`块并不是那么好.需要一种在模型级别定义排除属性以应用所有查询的方法! (2认同)

Mat*_*ley 13

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

defaultScope: {
    attributes: { exclude: ['password'] },
},
scopes: {
    withPassword: {
        attributes: { },
    }
}
Run Code Online (Sandbox Code Playgroud)

这允许我默认排除密码并使用withPassword范围在需要时显式返回密码,例如在运行登录方法时.

userModel.scope('withPassword').findAll()
Run Code Online (Sandbox Code Playgroud)

这确保了在通过引用字段包括用户时不返回密码,例如

accountModel.findAll({
    include: [{
        model: userModel,
        as: 'user'
    }]
})
Run Code Online (Sandbox Code Playgroud)


Ari*_*via 5

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

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
Run Code Online (Sandbox Code Playgroud)

Github 要点


Ajm*_*med 5

我可以通过向返回的字段添加一个 getter 来实现此功能undefined

firstName: {
      type: DataTypes.STRING,
      get() {
        return undefined;
      }
    }
Run Code Online (Sandbox Code Playgroud)

当模型包含在另一个模型中时,接受的答案不起作用。

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