Mongoose Schema Enum属性不生效问题排查求助
问题:用户注册时指定的
role字段未生效,始终被设为默认值user 在开发用户模型userModel时,我为userSchema中的role字段设置了enum属性,可选值为['user', 'guide', 'lead-guide', 'admin'],默认值为user。但在Postman测试/signup路由时,无论请求体中传入的role是哪个有效值,最终创建的用户角色始终是默认的user。
相关代码片段
const mongoose = require('mongoose'); const validator = require('validator'); const bycrypt = require('bcryptjs'); const userSchema = new mongoose.Schema({ name: { type: String, required: [true, '用户必须填写姓名'], }, email: { type: String, required: [true, '用户必须填写邮箱'], unique: true, lowercase: true, validate: [validator.isEmail, '请提供有效的邮箱地址'], }, photo: { type: String, }, role: { type: String, enum: ['user', 'guide', 'lead-guide', 'admin'], default: 'user', }, password: { type: String, required: [true, '请设置密码'], minlength: 8, select: false, // 查询时隐藏该字段 }, passwordConfirm: { type: String, required: [true, '请确认密码'], validate: { // 仅在CREATE和SAVE操作时生效(更新操作不触发) validator: function (el) { return el === this.password; }, message: '密码与确认密码不一致!', }, }, passwordChangedAt: Date, }); // 密码加密中间件 userSchema.pre('save', async function (next) { // 仅当密码被修改时执行加密逻辑 if (!this.isModified('password')) return next(); // 使用bcrypt哈希密码,cost值设为12 this.password = await bycrypt.hash(this.password, 12); // 清除确认密码字段(仅用于输入验证,无需存入数据库) this.passwordConfirm = undefined; next(); }); // 密码验证实例方法(用于登录时校验密码) userSchema.methods.correctPassword = async function ( candidatePassword, userPassword, ) { // 返回密码比对结果(true/false) return bycrypt.compare(candidatePassword, userPassword); }; // 密码修改时间校验方法(用于JWT令牌有效性判断) userSchema.methods.changedPasswordAfter = function (JWTTimestamp) { if (this.passwordChangedAt) { // 将时间戳转换为秒级 const changedTimeStamp = parseInt( this.passwordChangedAt.getTime() / 1000, 10, ); console.log(changedTimeStamp, JWTTimestamp); // 如果令牌生成时间早于密码修改时间,说明密码已更新 return JWTTimestamp < changedTimeStamp; } // 返回false表示密码未修改 return false; }; // 创建User模型 const User = mongoose.model('User', userSchema); module.exports = User;
Postman请求体
{ "name":"Admin10", "email":"Admisnl13'24s0@gmail.com", "password":"pass1234", "passwordConfirm":"pass1234", "role":"admin" }
实际响应结果
{ "status": "success", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjY1NWYzMDBjZWJhOTQxMzM2MDA2YjFiNSIsImlhdCI6MTcwMDczNzAzNywiZXhwIjoxNzA4NTEzMDM3fQ.a474i9cMNIkeTkq4wA97PXQzhspfGzGQVc4expRM5mM", "data": { "user": { "role": "user", "_id": "655f300ceba941336006b1b5", "name": "Admin10", "email": "admisnl13'24s0@gmail.com", "password": "$2a$12$S8RCXsoAj2K6zZZgvLFXh.z1rrL0WoABnrg6NzUwRx2Dq2RsuqTQG", "__v": 0 } } }
问题排查与解决方案
核心原因:路由逻辑未传递role字段到用户创建流程
你的/signup路由处理代码大概率遗漏了role字段的传递,导致mongoose无法获取到请求体中的role值,只能使用默认值。
解决方法1:明确传递role字段
在创建用户时,确保解构请求体时包含role,并传入User.create()方法:
// 正确示例:解构包含role字段 const { name, email, password, passwordConfirm, role } = req.body; const user = await User.create({ name, email, password, passwordConfirm, role // 必须显式传入该字段 });
解决方法2:使用扩展运算符传递请求体(需配合参数校验)
如果需要传递所有合法字段,可以使用扩展运算符,但建议结合express-validator等中间件做参数校验,防止恶意字段注入:
// 配合校验中间件的示例 const user = await User.create({ ...req.body });
安全补充:限制高权限角色的设置
为了避免普通用户注册时设置admin等高权限角色,建议在创建用户前添加逻辑限制:
const userData = { ...req.body }; // 仅允许内部请求或特定权限的用户设置高权限角色 if (!req.isInternalRequest) { userData.role = 'user'; } const user = await User.create(userData);
内容的提问来源于stack exchange,提问作者yishak abrham
相关产品推荐
相关产品推荐

