我有这个模型user.js
import mongoose from "mongoose";
import crypto from "crypto";
const { ObjectId } = mongoose.Schema;
const userSchema = new mongoose.Schema(
{
//Basic Data
email: {
type: String,
trim: true,
required: true,
unique: true,
},
hashed_password: {
type: String,
required: true,
},
salt: {
type: String,
},
);
// virtual field
userSchema
.virtual("password")
.set(function (password) {
// create a temporarity variable called _password
this._password = password;
// generate salt
this.salt = this.makeSalt();
// encryptPassword
this.hashed_password = this.encryptPassword(password);
})
.get(function () {
return this._password;
});
// Methods
userSchema.methods = {
// Method Authenticate User
authenticate: function (plainText) {
const encryptP = this.encryptPassword(plainText);
console.log("Entro a Autenticate...");
console.log("Authenticate PlainText:", plainText);
console.log("Authenticate Hashed:", this.hashed_password);
console.log("Encript Pass:", encryptP);
return this.encryptPassword(plainText) === this.hashed_password; // Ture or False
},
// Method Encrypt Pass
encryptPassword: function (password) {
if (!password) return "";
try {
return crypto.createHmac("sha1", this.salt).update(password).digest("hex");
} catch (err) {
return "";
}
},
// Method Make Salt
makeSalt: function () {
return Math.round(new Date().valueOf() * Math.random()) + "";
},
};
// export default mongoose.model("User", userSchema);
module.exports = mongoose.models.User || mongoose.model("User", userSchema);
字符串
所有console.log的结果是:
Entro a Autenticate...
Authenticate PlainText: 1234567890
Authenticate Hashed: b4358d67e879145916c10ba00d66d78a946f4b53
Encript Pass: b4358d67e879145916c10ba00d66d78a946f4b53
型
.js文件工作正常。
我开始一个新的项目使用Typescript使用相同的逻辑和代码,但与typescript。
这是我的模型用户。ts:
import { Model, model, Schema, models } from "mongoose";
import crypto from "crypto";
// 1. Create an interface representing a document in MongoDB.
interface IUser {
email: string;
hashed_password?: string;
salt?: string;
//Virtual Field
_password?: string;
}
// Put all user instance methods in this interface:
interface IUserMethods {
authenticate(plainText: string): boolean;
encryptPassword(password: string): string;
makeSalt(): string;
}
// Create a new Model type that knows about IUserMethods...
type UserModel = Model<IUser, {}, IUserMethods>;
// 2. Create a Schema corresponding to the document interface.
const userSchema = new Schema<IUser, UserModel, IUserMethods>(
{
//Basic Data
email: {
type: String,
trim: true,
required: true,
unique: true,
},
hashed_password: {
type: String,
required: true,
},
salt: {
type: String,
},
);
//Virtuals
userSchema
.virtual("password")
.set(function (password:string) {
// create a temporarity variable called _password
this._password = password;
// generate salt
this.salt = this.makeSalt();
// encryptPassword
this.hashed_password = this.encryptPassword(password);
})
.get(function () {
return this._password;
});
// Methods
userSchema.methods = {
// Method Authenticate User
authenticate: function (plainText:string) {
const encryptP: any = this.encryptPassword(plainText);
console.log("Entro a Autenticate...");
console.log("Authenticate PlainText:", plainText);
console.log("Authenticate Hashed:", this.hashed_password);
console.log("Encript Pass:", encryptP);
return this.encryptPassword(plainText) === this.hashed_password; // Ture or False
},
// Method Encrypt Pass
encryptPassword: function (password:string) {
if (!password) return "";
try {
return crypto.createHmac("sha1", this.salt).update(password).digest("hex");
} catch (err) {
return "";
}
},
// Method Make Salt
makeSalt: function () {
return Math.round(new Date().valueOf() * Math.random()) + "";
},
};
export default models.User || model<IUser, UserModel>("User", userSchema);
型
使用此Typescript文件的所有控制台日志的结果是:
Entro a Autenticate...
Authenticate PlainText: 1234567890
Authenticate Hashed: undefined
Encript Pass:
型
问题似乎在于它处理类型的方式...
但毫无头绪。
编辑:
根据评论,我发现问题是白:
this.salt
this.hashed_password
型
在TS中显示为“undefined”,在JS中显示为字符串(应该如此)
2条答案
按热度按时间brccelvz1#
这段代码有多个问题。我将逐一检查它们,但在此之前,您的代码可能无法工作,因为在
crypto.createHmac("sha1", this.salt)
中,this.salt
可能未定义或与函数期望的类型不同。请在catch块中记录错误,而不是简单地返回空字符串。这应该会有所帮助。继续讨论问题:盐
在以下行中:
字符串
this.salt
不是salt,它是key。HMAC本质上是一个带密钥的hash。createHmac
函数的第二个参数期望key生成hash。稍后您将需要这个相同的key来验证hash。您可以使用它来实现与salt相同的功能,因为您可以阻止彩虹表攻击,但它并不完全相同,因为密钥应该是秘密的,而盐则不是。算法
如果您正在散列用户密码,请不要使用SHA-1。它被认为是损坏的。OWASP password storage cheat sheet有关于如何存储密码,使用什么参数的散列函数等的建议。Argon 2 id或scrypt应该没问题。
makeSalt
函数我希望这个函数的实现是出于演示/调试的目的,但如果不是,请不要像这样创建一个盐。创建随机盐的更好方法是使用
crypto.randomBytes
函数。如果你想要一个字符串,你可以用相关的编码调用toString
。例如,对于十六进制,你可以这样做:型
pnwntuvh2#
已解决:
问题不在于Typescript,而在于对象“this”,这个对象是在方法被调用时创建的。
方法是这样调用的
字符串
mongoose上的userDB对象是挂载的“this”对象。因此,this.salt和this.hashed_password必须包含在userDB对象中,以便在调用的方法上“拦截”。
安装在“this”上的userDB对象不包含salt和hashed_pass,所以我添加了它们,代码工作得很好!