mongoose Next js 13.5中的TypeScript方法和虚拟Moose模型问题

u2nhd7ah  于 12个月前  发布在  Go
关注(0)|答案(2)|浏览(139)

我有这个模型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中显示为字符串(应该如此)

brccelvz

brccelvz1#

这段代码有多个问题。我将逐一检查它们,但在此之前,您的代码可能无法工作,因为在crypto.createHmac("sha1", this.salt)中,this.salt可能未定义或与函数期望的类型不同。请在catch块中记录错误,而不是简单地返回空字符串。这应该会有所帮助。继续讨论问题:

在以下行中:

return crypto.createHmac("sha1", this.salt).update(password).digest("hex");

字符串
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。例如,对于十六进制,你可以这样做:

// generate a 16 byte random salt
const salt = crypto.randomBytes(16).toString('hex');
return salt;

pnwntuvh

pnwntuvh2#

已解决:
问题不在于Typescript,而在于对象“this”,这个对象是在方法被调用时创建的。
方法是这样调用的

userDB.authenticate(passIn);

字符串
mongoose上的userDB对象是挂载的“this”对象。因此,this.salt和this.hashed_password必须包含在userDB对象中,以便在调用的方法上“拦截”。
安装在“this”上的userDB对象不包含salt和hashed_pass,所以我添加了它们,代码工作得很好!

相关问题