J'utilise Sequelize pour effectuer une recherche de base de données pour un enregistrement utilisateur et je veux que le comportement par défaut du modèle ne renvoie pas le password
champ pour cet enregistrement. Le champ password
est un hachage mais je ne veux toujours pas le renvoyer.
J'ai plusieurs options qui fonctionneront, mais aucune ne semble particulièrement bonne:
Créez une méthode de classe personnalisée findWithoutPassword
pour le modèle User
et dans cette méthode, effectuez une User.find
avec le attributes
défini comme indiqué dans le Sequelize docs
Faites un User.find
et filtrer les résultats dans le contrôleur (non préféré)
Utilisez une autre bibliothèque pour supprimer les attributs indésirables
Y a-t-il une meilleure façon? Le mieux serait qu'il y ait un moyen de spécifier dans la définition du modèle Sequelize de ne jamais retourner le champ password
, mais je n'ai pas trouvé de moyen de le faire.
Je suggère de remplacer la fonction toJSON
:
sequelize.define('user', attributes, {
instanceMethods: {
toJSON: function () {
var values = Object.assign({}, this.get());
delete values.password;
return values;
}
}
});
Ou dans la suite v4
const User = sequelize.define('user', attributes, {});
User.prototype.toJSON = function () {
var values = Object.assign({}, this.get());
delete values.password;
return values;
}
toJSON
est appelé lorsque les données sont retournées à l'utilisateur, donc les utilisateurs finaux ne verront pas le champ du mot de passe, mais il sera toujours disponible dans votre code.
Object.assign
clone l'objet retourné - Sinon, vous supprimerez complètement la propriété de l'instance.
Une autre façon consiste à ajouter une étendue par défaut au modèle utilisateur.
Ajoutez ceci dans l'objet d'options du modèle
defaultScope: {
attributes: { exclude: ['password'] },
}
Ou vous pouvez créer une portée distincte pour l'utiliser uniquement dans certaines requêtes.
Ajoutez ceci dans l'objet d'options du modèle
scopes: {
withoutPassword: {
attributes: { exclude: ['password'] },
}
}
Ensuite, vous pouvez l'utiliser dans des requêtes
User.scope('withoutPassword').findAll();
Peut-être que vous pouvez simplement ajouter exclude
à votre attribut lorsque vous find
, ressemble à ceci:
var User = sequelize.define('user', attributes);
User.findAll({
attributes: {
exclude: ['password']
}
});
Lisez le docs pour plus de détails
J'aime utiliser une combinaison des deux réponses de Pawan et déclarer ce qui suit:
defaultScope: {
attributes: { exclude: ['password'] },
},
scopes: {
withPassword: {
attributes: { },
}
}
Cela me permet d'exclure le mot de passe par défaut et d'utiliser la portée withPassword
pour renvoyer explicitement le mot de passe en cas de besoin, comme lors de l'exécution d'une méthode de connexion.
userModel.scope('withPassword').findAll()
Cela garantit que le mot de passe n'est pas retourné lors de l'inclusion de l'utilisateur via un champ référencé, par ex.
accountModel.findAll({
include: [{
model: userModel,
as: 'user'
}]
})
J'ai pu faire fonctionner cela en ajoutant un getter au champ qui renvoie undefined
firstName: {
type: DataTypes.STRING,
get() {
return undefined;
}
}
réponse acceptée ne fonctionne pas lorsque le modèle est inclus à partir d'un autre modèle.
J'avais un champ virtuel, disons fullName
qui dépend des champs que je voulais cacher, disons firstName
et lastName
. Et la solution basée sur defaultScope
ne fonctionne pas dans ce cas.
il y a un plugin pour attributs de portée comme discuté ici .
je suis allé avec le remplacement comme mentionné dans la réponse acceptée, sauf que j'ai appelé l'original toJSON
plutôt que get
avec this.constructor.super_.prototype.toJSON.apply(this, arguments)
comme décrit dans les documentation api
Le code ci-dessous a fonctionné pour moi. Nous voulions accéder aux attributs d'instance au moment de l'exécution mais les supprimer avant d'envoyer les données au client.
const Sequelize = require('sequelize')
const sequelize = new Sequelize('postgres://user:[email protected]: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