新增 IPasswordHasher 抽象 + bcryptHasher(默认,lazy import)+ plainHasher
(测试用)。Password 字段 reqFilter 和 UserModule.verifyPassword 都走
`Shrimp.passwordHasher`,消费方在启动期换实现就能彻底跳过 bcrypt。
import { Shrimp, plainHasher } from "shrimp-server"
Shrimp.passwordHasher = plainHasher
测试覆盖默认值、plain 端到端登录、自定义 hasher 被调用。
52 lines
1.7 KiB
TypeScript
52 lines
1.7 KiB
TypeScript
/**
|
|
* 密码哈希抽象 — 把 bcrypt 从 Shrimp 核心彻底剥离
|
|
*
|
|
* 默认仍用 bcrypt(行业标准,Shrimp 大多数场景都需要),但通过抽象接口
|
|
* 让消费方可以:
|
|
* - 完全不装 bcrypt(走 plainHasher / 自己写一个 argon2 / scrypt 等)
|
|
* - 在测试里跳过哈希计算开销
|
|
* - 接入已有的密码系统(SHA256 + salt 之类)
|
|
*
|
|
* 配置方式:
|
|
* import { Shrimp, plainHasher } from "shrimp-server"
|
|
* Shrimp.passwordHasher = plainHasher // 或自己实现的 IPasswordHasher
|
|
*/
|
|
|
|
export interface IPasswordHasher {
|
|
/** 把明文密码加密成存储字符串 */
|
|
hash(plain: string): Promise<string>
|
|
/** 校验明文密码是否匹配已存储的哈希 */
|
|
verify(plain: string, hashed: string): Promise<boolean>
|
|
}
|
|
|
|
/**
|
|
* 默认实现 — bcrypt
|
|
*
|
|
* 通过动态 import 加载,确保只有真正调用 hash/verify 时才 require('bcrypt')。
|
|
* 这样消费方:不创建 Password 字段 + 不登录的话,可以完全不装 bcrypt。
|
|
*/
|
|
export const bcryptHasher: IPasswordHasher = {
|
|
async hash(plain: string): Promise<string> {
|
|
const bcrypt = await import("bcrypt")
|
|
return bcrypt.hash(plain, 10)
|
|
},
|
|
async verify(plain: string, hashed: string): Promise<boolean> {
|
|
const bcrypt = await import("bcrypt")
|
|
return bcrypt.compare(plain, hashed)
|
|
},
|
|
}
|
|
|
|
/**
|
|
* 明文实现 — 仅用于测试 / 开发环境 / 自己已经在上层做了加密
|
|
*
|
|
* **生产环境严禁使用**。存储明文密码的后果你懂的。
|
|
*/
|
|
export const plainHasher: IPasswordHasher = {
|
|
async hash(plain: string): Promise<string> {
|
|
return plain
|
|
},
|
|
async verify(plain: string, hashed: string): Promise<boolean> {
|
|
return plain === hashed
|
|
},
|
|
}
|