/** * 密码加密工具(SHA-256 → 小写 hex) * * 安全上下文(HTTPS 或 localhost)下使用原生 Web Crypto API; * 非安全上下文(HTTP + 局域网/IP 访问,此时 crypto.subtle 为 undefined) * 下回退到纯 JS 实现 js-sha256,保证产物一致,登录不再卡死。 * 两条路径对同一字符串产出的 SHA-256 小写 hex 完全相同。 */ import { sha256 } from 'js-sha256' /** 当前环境是否可用原生 Web Crypto(即处于安全上下文) */ function hasSubtleCrypto(): boolean { return typeof crypto !== 'undefined' && typeof crypto.subtle?.digest === 'function' } /** 原生 Web Crypto SHA-256 → 小写 hex */ async function subtleSha256Hex(input: string): Promise { const data = new TextEncoder().encode(input) const hashBuffer = await crypto.subtle.digest('SHA-256', data) return Array.from(new Uint8Array(hashBuffer)) .map((b) => b.toString(16).padStart(2, '0')) .join('') } /** 统一入口:优先原生,回退纯 JS */ async function sha256Hex(input: string): Promise { if (hasSubtleCrypto()) { return subtleSha256Hex(input) } return sha256(input) } /** * 使用 SHA-256 算法哈希密码 * @param password 明文密码 * @returns 哈希后的十六进制字符串(小写) */ export async function hashPassword(password: string): Promise { if (!password) return '' try { return await sha256Hex(password) } catch (error) { console.error('密码哈希失败:', error) throw new Error('密码加密失败') } } /** * 简单的加盐哈希(可选,用于增强安全性) * @param password 明文密码 * @param salt 盐值 * @returns 哈希后的十六进制字符串(小写) */ export async function hashPasswordWithSalt(password: string, salt: string): Promise { if (!password) return '' try { return await sha256Hex(password + salt) } catch (error) { console.error('密码哈希失败:', error) throw new Error('密码加密失败') } }