Sequelize: don't return password

孤街醉人 提交于 2019-12-17 22:14:59

问题


I'm using Sequelize to do a DB find for a user record, and I want the default behavior of the model to not return the password field for that record. The password field is a hash but I still don't want to return it.

I have several options that will work, but none seems particularly good:

  1. Create a custom class method findWithoutPassword for the User model and within that method do a User.find with the attributes set as shown in the Sequelize docs

  2. Do a normal User.find and filter the results in the controller (not preferred)

  3. Use some other library to strip off unwanted attributes

Is there a better way? Best of all would be if there is a way to specify in the Sequelize model definition to never return the password field, but I haven't found a way to do that.


回答1:


I would suggest overriding the toJSON function:

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

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

Or in sequelize v4

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

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

  delete values.password;
  return values;
}

toJSON is called when the data is returned to the user, so end users won't see the password field, but it will still be available in your code.

Object.assign clones the returned object - Otherwise you will completely delete the property from the instance.




回答2:


Another way is to add a default scope to the User model.

Add this in the model's options object

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

Or you can create a separate scope to use it only in certain queries.

Add this in the model's options object

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

Then you can use it in queries

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



回答3:


Maybe you can just add exclude at your attribute when you find, look like this:

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

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

Read the docs for more details




回答4:


I like to use a combination of both of Pawan's answers and declare the following:

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

This allows me to exclude the password by default and use the withPassword scope to explicitly return the password when needed, such as when running a login method.

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

This ensure that the password is not returned when including the user via a referenced field, e.g.

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



回答5:


there's a plugin for scoping attributes as discussed here.

i went with the override as mentioned in the accepted answer, except i called the original toJSON rather than get with this.constructor.super_.prototype.toJSON.apply(this, arguments) as described in the api docs




回答6:


The code below worked for me. We wanted access to the instance attributes at runtime but remove them before sending the data to the client.

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




回答7:


I was able to get this working by adding a getter to the field which returns undefined

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

The accepted answer does not work when the model is included from another model.

I had a virtual field, say fullName that depends on the fields that I wanted to hide, say firstName and lastName. And the solution based on defaultScope does not work in this case.



来源:https://stackoverflow.com/questions/27972271/sequelize-dont-return-password

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!