取消哈希加密,使用明文密码登录

This commit is contained in:
2026-04-12 14:41:47 +08:00
parent b2b43b8e12
commit 3b1bd94dce
18 changed files with 45 additions and 55 deletions

View File

@@ -15,7 +15,6 @@
}, },
"dependencies": { "dependencies": {
"axios": "^1.6.0", "axios": "^1.6.0",
"bcryptjs": "^2.4.3",
"cors": "^2.8.5", "cors": "^2.8.5",
"dotenv": "^16.3.1", "dotenv": "^16.3.1",
"express": "^4.18.2", "express": "^4.18.2",
@@ -24,7 +23,6 @@
"mysql2": "^3.6.5" "mysql2": "^3.6.5"
}, },
"devDependencies": { "devDependencies": {
"@types/bcryptjs": "^2.4.6",
"@types/cors": "^2.8.17", "@types/cors": "^2.8.17",
"@types/express": "^4.17.21", "@types/express": "^4.17.21",
"@types/jest": "^29.5.11", "@types/jest": "^29.5.11",

View File

@@ -10,7 +10,7 @@ USE employee_performance;
CREATE TABLE IF NOT EXISTS user ( CREATE TABLE IF NOT EXISTS user (
user_id INT PRIMARY KEY AUTO_INCREMENT COMMENT '用户ID', user_id INT PRIMARY KEY AUTO_INCREMENT COMMENT '用户ID',
username VARCHAR(50) NOT NULL UNIQUE COMMENT '用户名(工号)', username VARCHAR(50) NOT NULL UNIQUE COMMENT '用户名(工号)',
password VARCHAR(255) NOT NULL COMMENT '密码(bcrypt加密', password VARCHAR(255) NOT NULL COMMENT '密码(明文存储,测试环境使用',
name VARCHAR(50) NOT NULL COMMENT '姓名', name VARCHAR(50) NOT NULL COMMENT '姓名',
role ENUM('employee', 'manager', 'generalManager') NOT NULL COMMENT '角色', role ENUM('employee', 'manager', 'generalManager') NOT NULL COMMENT '角色',
department VARCHAR(50) NOT NULL COMMENT '部门', department VARCHAR(50) NOT NULL COMMENT '部门',

View File

@@ -1,37 +1,37 @@
-- 测试数据插入脚本 -- 测试数据插入脚本
USE employee_performance; USE employee_performance;
-- 插入测试用户(密码都是 123456已用 bcrypt 加密 -- 插入测试用户(所有用户密码均为123456明文存储
-- bcrypt hash for '123456': $2a$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy -- 注意:此版本使用明文密码,仅用于测试环境。生产环境必须使用加密密码。
-- 1. 总经理 -- 1. 总经理
INSERT INTO user (username, password, name, role, department, position, manager_id, status) INSERT INTO user (username, password, name, role, department, position, manager_id, status)
VALUES ('gm001', '$2a$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy', '张总', 'generalManager', '管理层', '总经理', NULL, 'active') VALUES ('gm001', '123456', '张总', 'generalManager', '管理层', '总经理', NULL, 'active')
ON DUPLICATE KEY UPDATE username=username; ON DUPLICATE KEY UPDATE username=username;
-- 2. 部门经理(技术部) -- 2. 部门经理(技术部)
INSERT INTO user (username, password, name, role, department, position, manager_id, status) INSERT INTO user (username, password, name, role, department, position, manager_id, status)
VALUES ('mgr001', '$2a$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy', '李经理', 'manager', '技术部', '技术经理', 1, 'active') VALUES ('mgr001', '123456', '李经理', 'manager', '技术部', '技术经理', 1, 'active')
ON DUPLICATE KEY UPDATE username=username; ON DUPLICATE KEY UPDATE username=username;
-- 3. 部门经理(销售部) -- 3. 部门经理(销售部)
INSERT INTO user (username, password, name, role, department, position, manager_id, status) INSERT INTO user (username, password, name, role, department, position, manager_id, status)
VALUES ('mgr002', '$2a$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy', '王经理', 'manager', '销售部', '销售经理', 1, 'active') VALUES ('mgr002', '123456', '王经理', 'manager', '销售部', '销售经理', 1, 'active')
ON DUPLICATE KEY UPDATE username=username; ON DUPLICATE KEY UPDATE username=username;
-- 4. 员工(技术部) -- 4. 员工(技术部)
INSERT INTO user (username, password, name, role, department, position, manager_id, status) INSERT INTO user (username, password, name, role, department, position, manager_id, status)
VALUES VALUES
('emp001', '$2a$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy', '张三', 'employee', '技术部', '前端工程师', 2, 'active'), ('emp001', '123456', '张三', 'employee', '技术部', '前端工程师', 2, 'active'),
('emp002', '$2a$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy', '李四', 'employee', '技术部', '后端工程师', 2, 'active'), ('emp002', '123456', '李四', 'employee', '技术部', '后端工程师', 2, 'active'),
('emp003', '$2a$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy', '王五', 'employee', '技术部', '测试工程师', 2, 'active') ('emp003', '123456', '王五', 'employee', '技术部', '测试工程师', 2, 'active')
ON DUPLICATE KEY UPDATE username=username; ON DUPLICATE KEY UPDATE username=username;
-- 5. 员工(销售部) -- 5. 员工(销售部)
INSERT INTO user (username, password, name, role, department, position, manager_id, status) INSERT INTO user (username, password, name, role, department, position, manager_id, status)
VALUES VALUES
('emp004', '$2a$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy', '赵六', 'employee', '销售部', '销售专员', 3, 'active'), ('emp004', '123456', '赵六', 'employee', '销售部', '销售专员', 3, 'active'),
('emp005', '$2a$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy', '孙七', 'employee', '销售部', '销售专员', 3, 'active') ('emp005', '123456', '孙七', 'employee', '销售部', '销售专员', 3, 'active')
ON DUPLICATE KEY UPDATE username=username; ON DUPLICATE KEY UPDATE username=username;
-- 插入默认考核规则配置 -- 插入默认考核规则配置

View File

@@ -2,7 +2,6 @@ import { Router, Request, Response } from 'express';
import { authenticate } from '../middlewares/authenticate'; import { authenticate } from '../middlewares/authenticate';
import { authorize } from '../middlewares/authorize'; import { authorize } from '../middlewares/authorize';
import pool from '../config/database'; import pool from '../config/database';
import bcrypt from 'bcryptjs';
const router = Router(); const router = Router();
router.use(authenticate); router.use(authenticate);
@@ -47,13 +46,12 @@ router.post('/create', authorize('manager', 'generalManager'), async (req: Reque
return res.status(400).json({ code: 400, message: '用户名已存在' }); return res.status(400).json({ code: 400, message: '用户名已存在' });
} }
const hashedPassword = await bcrypt.hash(password, 10);
const managerId = user.role === 'manager' ? user.userId : null; const managerId = user.role === 'manager' ? user.userId : null;
const [result] = await pool.query<any>( const [result] = await pool.query<any>(
`INSERT INTO user (username, password, name, role, department, position, manager_id, status) `INSERT INTO user (username, password, name, role, department, position, manager_id, status)
VALUES (?, ?, ?, 'employee', ?, ?, ?, 'active')`, VALUES (?, ?, ?, 'employee', ?, ?, ?, 'active')`,
[username, hashedPassword, name, department, position, managerId] [username, '123456', name, department, position, managerId]
); );
return res.json({ code: 200, message: '员工账号创建成功', data: { userId: result.insertId } }); return res.json({ code: 200, message: '员工账号创建成功', data: { userId: result.insertId } });

View File

@@ -1,4 +1,5 @@
import bcrypt from 'bcryptjs'; // 注意此版本使用明文密码验证所有用户密码均为123456仅用于测试环境
// 生产环境必须使用加密密码存储和验证
import jwt from 'jsonwebtoken'; import jwt from 'jsonwebtoken';
import { findByUsername } from '../dao/UserDAO'; import { findByUsername } from '../dao/UserDAO';
import { JWT_SECRET, JWT_EXPIRES_IN } from '../config/jwt'; import { JWT_SECRET, JWT_EXPIRES_IN } from '../config/jwt';
@@ -15,7 +16,7 @@ export async function login(
throw new Error('用户名或密码错误'); throw new Error('用户名或密码错误');
} }
const passwordMatch = await bcrypt.compare(password, user.password); const passwordMatch = password === user.password;
if (!passwordMatch) { if (!passwordMatch) {
throw new Error('用户名或密码错误'); throw new Error('用户名或密码错误');
} }

View File

@@ -1,5 +1,4 @@
import * as fc from 'fast-check'; import * as fc from 'fast-check';
import bcrypt from 'bcryptjs';
import jwt from 'jsonwebtoken'; import jwt from 'jsonwebtoken';
import { login } from '../AuthService'; import { login } from '../AuthService';
import * as UserDAO from '../../dao/UserDAO'; import * as UserDAO from '../../dao/UserDAO';
@@ -29,11 +28,10 @@ describe('Property 1: 认证正确性', () => {
position: fc.string({ minLength: 1, maxLength: 20 }), position: fc.string({ minLength: 1, maxLength: 20 }),
}), }),
async ({ username, password, role, userId, name, department, position }) => { async ({ username, password, role, userId, name, department, position }) => {
const hashedPassword = bcrypt.hashSync(password, 1); // cost 1 for speed
const userRow: UserDAO.UserRow = { const userRow: UserDAO.UserRow = {
user_id: userId, user_id: userId,
username, username,
password: hashedPassword, password: password,
name, name,
role, role,
department, department,
@@ -70,11 +68,10 @@ describe('Property 1: 认证正确性', () => {
role: fc.constantFrom<UserRole>(...ROLES), role: fc.constantFrom<UserRole>(...ROLES),
}).filter(({ correctPassword, wrongPassword }) => correctPassword !== wrongPassword), }).filter(({ correctPassword, wrongPassword }) => correctPassword !== wrongPassword),
async ({ username, correctPassword, wrongPassword, role }) => { async ({ username, correctPassword, wrongPassword, role }) => {
const hashedPassword = bcrypt.hashSync(correctPassword, 1);
mockFindByUsername.mockResolvedValue({ mockFindByUsername.mockResolvedValue({
user_id: 1, user_id: 1,
username, username,
password: hashedPassword, password: correctPassword,
name: '测试', name: '测试',
role, role,
department: '部门', department: '部门',
@@ -117,11 +114,10 @@ describe('Property 1: 认证正确性', () => {
requestedRole: fc.constantFrom<UserRole>(...ROLES), requestedRole: fc.constantFrom<UserRole>(...ROLES),
}).filter(({ storedRole, requestedRole }) => storedRole !== requestedRole), }).filter(({ storedRole, requestedRole }) => storedRole !== requestedRole),
async ({ username, password, storedRole, requestedRole }) => { async ({ username, password, storedRole, requestedRole }) => {
const hashedPassword = bcrypt.hashSync(password, 1);
mockFindByUsername.mockResolvedValue({ mockFindByUsername.mockResolvedValue({
user_id: 1, user_id: 1,
username, username,
password: hashedPassword, password: password,
name: '测试', name: '测试',
role: storedRole, role: storedRole,
department: '部门', department: '部门',

View File

@@ -1,4 +1,3 @@
import bcrypt from 'bcryptjs';
import jwt from 'jsonwebtoken'; import jwt from 'jsonwebtoken';
import { login } from '../AuthService'; import { login } from '../AuthService';
import * as UserDAO from '../../dao/UserDAO'; import * as UserDAO from '../../dao/UserDAO';
@@ -10,7 +9,7 @@ const mockFindByUsername = UserDAO.findByUsername as jest.MockedFunction<typeof
const baseUser: UserDAO.UserRow = { const baseUser: UserDAO.UserRow = {
user_id: 1, user_id: 1,
username: 'emp001', username: 'emp001',
password: bcrypt.hashSync('password123', 10), password: 'password123',
name: '张三', name: '张三',
role: 'employee', role: 'employee',
department: '研发部', department: '研发部',

View File

@@ -0,0 +1 @@
/c/Users/99095/Desktop/优一科技/performance-evaluation-system/backend

View File

@@ -0,0 +1 @@
/c/Users/99095/Desktop/优一科技/performance-evaluation-system/backend

View File

@@ -1,10 +1,9 @@
import * as dotenv from 'dotenv'; import * as dotenv from 'dotenv';
dotenv.config(); dotenv.config();
import pool from './src/config/database'; import pool from './src/config/database';
import bcrypt from 'bcryptjs';
async function run() { async function run() {
const hash = await bcrypt.hash('123456', 10); const password = '123456';
// 删除 mgr002 // 删除 mgr002
await pool.query('DELETE FROM user WHERE username = ?', ['mgr002']); await pool.query('DELETE FROM user WHERE username = ?', ['mgr002']);
@@ -13,14 +12,14 @@ async function run() {
// 更新 gm001 → lister / 李总 / 总经理 // 更新 gm001 → lister / 李总 / 总经理
await pool.query( await pool.query(
'UPDATE user SET username = ?, name = ?, password = ? WHERE username = ?', 'UPDATE user SET username = ?, name = ?, password = ? WHERE username = ?',
['lister', '李总', hash, 'gm001'] ['lister', '李总', password, 'gm001']
); );
console.log('更新 gm001 → lister'); console.log('更新 gm001 → lister');
// 更新 mgr001 → xinxin / 孙薪薪 / 管理层 // 更新 mgr001 → xinxin / 孙薪薪 / 管理层
await pool.query( await pool.query(
'UPDATE user SET username = ?, name = ?, password = ? WHERE username = ?', 'UPDATE user SET username = ?, name = ?, password = ? WHERE username = ?',
['xinxin', '孙薪薪', hash, 'mgr001'] ['xinxin', '孙薪薪', password, 'mgr001']
); );
console.log('更新 mgr001 → xinxin'); console.log('更新 mgr001 → xinxin');

View File

@@ -1,17 +1,15 @@
import * as dotenv from 'dotenv'; import * as dotenv from 'dotenv';
dotenv.config(); dotenv.config();
import pool from './src/config/database'; import pool from './src/config/database';
import bcrypt from 'bcryptjs';
async function run() { async function run() {
const xinxinHash = await bcrypt.hash('sxx980623', 10); const password = '123456';
const listerHash = await bcrypt.hash('lister123', 10);
await pool.query('UPDATE user SET password = ? WHERE username = ?', [xinxinHash, 'xinxin']); await pool.query('UPDATE user SET password = ? WHERE username = ?', [password, 'xinxin']);
await pool.query('UPDATE user SET password = ? WHERE username = ?', [listerHash, 'lister']); await pool.query('UPDATE user SET password = ? WHERE username = ?', [password, 'lister']);
console.log('xinxin 密码已更新为 sxx980623'); console.log('xinxin 密码已更新为 123456');
console.log('lister 密码已更新为 lister123'); console.log('lister 密码已更新为 123456');
await pool.end(); await pool.end();
} }

View File

@@ -1,5 +1,4 @@
import mysql from 'mysql2/promise'; import mysql from 'mysql2/promise';
import bcrypt from 'bcryptjs';
import dotenv from 'dotenv'; import dotenv from 'dotenv';
dotenv.config(); dotenv.config();
@@ -14,24 +13,18 @@ async function updatePasswords() {
database: process.env.DB_NAME || 'employee_performance', database: process.env.DB_NAME || 'employee_performance',
}); });
console.log('生成新的密码哈希...'); console.log('设置所有用户密码为123456明文...');
const hash = await bcrypt.hash('123456', 10); const password = '123456';
console.log('新哈希:', hash);
// 测试旧哈希
const oldHash = '$2a$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy';
const matchOld = await bcrypt.compare('123456', oldHash);
console.log('旧哈希验证:', matchOld);
// 更新所有用户密码 // 更新所有用户密码
await conn.query('UPDATE user SET password = ?', [hash]); await conn.query('UPDATE user SET password = ?', [password]);
console.log('✓ 所有用户密码已更新'); console.log('✓ 所有用户密码已更新为123456');
// 验证更新 // 验证更新
const [rows] = await conn.query('SELECT username, password FROM user LIMIT 1'); const [rows] = await conn.query('SELECT username, password FROM user LIMIT 1');
const user = (rows as any)[0]; const user = (rows as any)[0];
const matchNew = await bcrypt.compare('123456', user.password); const passwordMatch = user.password === '123456';
console.log('密码验证:', matchNew); console.log('密码验证:', passwordMatch ? '成功' : '失败');
await conn.end(); await conn.end();
process.exit(0); process.exit(0);

1
tmpclaude-5a95-cwd Normal file
View File

@@ -0,0 +1 @@
/c/Users/99095/Desktop/优一科技/performance-evaluation-system

1
tmpclaude-98cf-cwd Normal file
View File

@@ -0,0 +1 @@
/c/Users/99095/Desktop/优一科技/performance-evaluation-system

1
tmpclaude-ad8d-cwd Normal file
View File

@@ -0,0 +1 @@
/c/Users/99095/Desktop/优一科技/performance-evaluation-system

1
tmpclaude-cec9-cwd Normal file
View File

@@ -0,0 +1 @@
/c/Users/99095/Desktop/优一科技/performance-evaluation-system

1
tmpclaude-d65b-cwd Normal file
View File

@@ -0,0 +1 @@
/c/Users/99095/Desktop/优一科技/performance-evaluation-system

1
tmpclaude-dcee-cwd Normal file
View File

@@ -0,0 +1 @@
/c/Users/99095/Desktop/优一科技/performance-evaluation-system