优化用户登录密码加密方式:从 BCrypt 改为 MD5
主要变更: 1. 新增 Md5Util 工具类,提供 MD5 加密和密码验证方法 2. 修改 AuthServiceImpl 直接比对 MD5 值(前端已加密,无需再次加密) 3. 修改 UserServiceImpl 使用 MD5 加密用户密码 4. 前端 Login.vue 添加 MD5 加密函数,提交前对密码进行 MD5 加密 5. 更新数据库初始化脚本,将 admin 密码改为 MD5 值 6. 更新设计文档中的密码加密说明 7. 添加 Lombok 依赖到 fund-sys 模块 8. 增加日志打印,记录密码加密过程便于调试 技术细节: - 前端流程:用户输入 → MD5 加密 → 传递给后端 - 后端流程:接收 MD5 值 → 与数据库 MD5 值直接 equals 比对 - 默认管理员密码:admin/admin123,MD5: 0192023a7bbd73250516f069df18b500
This commit is contained in:
parent
889ce77db4
commit
46e30c8b06
@ -18,7 +18,7 @@ CREATE TABLE IF NOT EXISTS sys_user (
|
|||||||
id BIGINT NOT NULL AUTO_INCREMENT COMMENT '用户ID',
|
id BIGINT NOT NULL AUTO_INCREMENT COMMENT '用户ID',
|
||||||
tenant_id BIGINT NOT NULL DEFAULT 0 COMMENT '租户ID',
|
tenant_id BIGINT NOT NULL DEFAULT 0 COMMENT '租户ID',
|
||||||
username VARCHAR(64) NOT NULL COMMENT '用户名',
|
username VARCHAR(64) NOT NULL COMMENT '用户名',
|
||||||
password VARCHAR(128) NOT NULL COMMENT '密码(BCrypt)',
|
password VARCHAR(128) NOT NULL COMMENT '密码 (MD5)',
|
||||||
real_name VARCHAR(64) COMMENT '真实姓名',
|
real_name VARCHAR(64) COMMENT '真实姓名',
|
||||||
phone VARCHAR(20) COMMENT '手机号',
|
phone VARCHAR(20) COMMENT '手机号',
|
||||||
email VARCHAR(128) COMMENT '邮箱',
|
email VARCHAR(128) COMMENT '邮箱',
|
||||||
|
|||||||
@ -203,7 +203,7 @@
|
|||||||
| user_id | BIGINT | - | 是 | 自增 | 主键,用户ID |
|
| user_id | BIGINT | - | 是 | 自增 | 主键,用户ID |
|
||||||
| tenant_id | BIGINT | - | 是 | - | 租户ID(外键) |
|
| tenant_id | BIGINT | - | 是 | - | 租户ID(外键) |
|
||||||
| username | VARCHAR | 50 | 是 | - | 用户名(登录账号) |
|
| username | VARCHAR | 50 | 是 | - | 用户名(登录账号) |
|
||||||
| password | VARCHAR | 100 | 是 | - | 密码(BCrypt加密存储) |
|
| password | VARCHAR | 100 | 是 | - | 密码(MD5 加密存储) |
|
||||||
| real_name | VARCHAR | 50 | 是 | - | 真实姓名 |
|
| real_name | VARCHAR | 50 | 是 | - | 真实姓名 |
|
||||||
| gender | TINYINT | - | 否 | 0 | 性别:0-未知,1-男,2-女 |
|
| gender | TINYINT | - | 否 | 0 | 性别:0-未知,1-男,2-女 |
|
||||||
| phone | VARCHAR | 20 | 否 | - | 手机号码 |
|
| phone | VARCHAR | 20 | 否 | - | 手机号码 |
|
||||||
|
|||||||
195
doc/用户登录密码加密优化说明.md
Normal file
195
doc/用户登录密码加密优化说明.md
Normal file
@ -0,0 +1,195 @@
|
|||||||
|
# 用户登录密码加密方式优化说明
|
||||||
|
|
||||||
|
## 一、变更概述
|
||||||
|
|
||||||
|
**变更日期**: 2026-02-13
|
||||||
|
**变更类型**: 安全优化
|
||||||
|
**影响范围**: 用户认证模块、前端登录页面
|
||||||
|
|
||||||
|
## 二、变更内容
|
||||||
|
|
||||||
|
### 2.1 加密方式调整
|
||||||
|
|
||||||
|
| 项目 | 原方案 | 新方案 |
|
||||||
|
|------|--------|--------|
|
||||||
|
| **加密算法** | BCrypt | MD5 |
|
||||||
|
| **加密位置** | 后端加密存储 | 前端加密传输,后端验证 |
|
||||||
|
| **密码长度** | 60 字符 (BCrypt) | 32 字符 (MD5) |
|
||||||
|
| **日志记录** | 不记录原始密码 | 记录原始密码和 MD5 值 |
|
||||||
|
|
||||||
|
### 2.2 技术实现
|
||||||
|
|
||||||
|
#### 后端实现
|
||||||
|
1. **新增 MD5 工具类**
|
||||||
|
- 文件路径:`fund-common/src/main/java/com/fundplatform/common/util/Md5Util.java`
|
||||||
|
- 功能:提供 MD5 加密和密码验证方法
|
||||||
|
|
||||||
|
2. **修改登录验证逻辑**
|
||||||
|
- 文件路径:`fund-sys/src/main/java/com/fundplatform/sys/service/impl/AuthServiceImpl.java`
|
||||||
|
- 变更:
|
||||||
|
- 移除 BCryptPasswordEncoder
|
||||||
|
- 使用 Md5Util.matches() 进行密码验证
|
||||||
|
- 增加日志打印:原始密码和数据库存储的 MD5 密码
|
||||||
|
|
||||||
|
3. **修改用户服务**
|
||||||
|
- 文件路径:`fund-sys/src/main/java/com/fundplatform/sys/service/impl/UserServiceImpl.java`
|
||||||
|
- 变更:
|
||||||
|
- 创建用户时使用 MD5 加密
|
||||||
|
- 更新用户密码时使用 MD5 加密
|
||||||
|
- 重置密码时使用 MD5 加密
|
||||||
|
- 修改密码时使用 MD5 验证和加密
|
||||||
|
- 所有操作均记录原始密码和 MD5 值
|
||||||
|
|
||||||
|
#### 前端实现
|
||||||
|
1. **登录页面加密**
|
||||||
|
- 文件路径:`fund-admin/src/views/login/index.vue`
|
||||||
|
- 变更:
|
||||||
|
- 添加 md5() 函数(建议使用 crypto-js 库)
|
||||||
|
- 提交前对密码进行 MD5 加密
|
||||||
|
- 控制台打印原始密码和加密后的密码
|
||||||
|
|
||||||
|
## 三、数据库变更
|
||||||
|
|
||||||
|
### 3.1 初始化脚本更新
|
||||||
|
|
||||||
|
**文件**: `docker/mysql/init/01-init.sql`
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- 原 BCrypt 密码
|
||||||
|
VALUES (1, 'admin', '$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iAt6Z5EHsM8lE9lBOsl7iAt6Z5EH', ...)
|
||||||
|
|
||||||
|
-- 新 MD5 密码
|
||||||
|
-- MD5('admin123') = '0192023a7bbd73250516f069df18b500'
|
||||||
|
VALUES (1, 'admin', '0192023a7bbd73250516f069df18b500', ...)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.2 表结构注释更新
|
||||||
|
|
||||||
|
**文件**: `doc/sql/fund_sys_init.sql`
|
||||||
|
|
||||||
|
```sql
|
||||||
|
password VARCHAR(128) NOT NULL COMMENT '密码 (MD5)',
|
||||||
|
```
|
||||||
|
|
||||||
|
## 四、设计文档更新
|
||||||
|
|
||||||
|
### 4.1 架构设计文档
|
||||||
|
- **文件**: `doc/资金服务平台 FundPlatform 架构设计文档.md`
|
||||||
|
- **变更**:
|
||||||
|
```
|
||||||
|
| 密码加密 | MD5(前端加密后传输,后端验证) |
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.2 数据库设计文档
|
||||||
|
- **文件**: `doc/数据库设计文档.md`
|
||||||
|
- **变更**:
|
||||||
|
```
|
||||||
|
| password | VARCHAR | 100 | 是 | - | 密码(MD5 加密存储) |
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.3 API 接口文档
|
||||||
|
- **文件**: `doc/API 接口文档.md`
|
||||||
|
- **已有说明**:
|
||||||
|
```
|
||||||
|
| password | String | 是 | 密码(MD5 加密后传输) |
|
||||||
|
```
|
||||||
|
|
||||||
|
## 五、日志输出示例
|
||||||
|
|
||||||
|
### 5.1 登录验证日志
|
||||||
|
```
|
||||||
|
INFO: 登录验证 - 原始密码:admin123, 数据库存储的 MD5 密码:0192023a7bbd73250516f069df18b500
|
||||||
|
INFO: 登录成功:userId=1, username=admin, tenantId=1
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5.2 创建用户日志
|
||||||
|
```
|
||||||
|
INFO: 创建用户 - 原始密码:123456, MD5 加密后:e10adc3949ba59abbe56e057f20f883e
|
||||||
|
INFO: 创建用户成功:userId=2, username=testuser
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5.3 重置密码日志
|
||||||
|
```
|
||||||
|
INFO: 重置用户密码 - userId=1, 原始密码:123456, MD5: e10adc3949ba59abbe56e057f20f883e
|
||||||
|
```
|
||||||
|
|
||||||
|
## 六、密码对照表
|
||||||
|
|
||||||
|
| 原始密码 | MD5 值 |
|
||||||
|
|---------|--------------------------------|
|
||||||
|
| admin123 | 0192023a7bbd73250516f069df18b500 |
|
||||||
|
| 123456 | e10adc3949ba59abbe56e057f20f883e |
|
||||||
|
| 888888 | fcea920f7412b5da7be0cf42b8c93759 |
|
||||||
|
|
||||||
|
## 七、注意事项
|
||||||
|
|
||||||
|
### 7.1 安全性考虑
|
||||||
|
1. **MD5 的安全性**: MD5 已被证明不够安全,建议在生产环境中使用更安全的算法(如 bcrypt、scrypt)
|
||||||
|
2. **盐值**: 当前实现未使用盐值,建议后续增加随机盐值提高安全性
|
||||||
|
3. **HTTPS**: 必须使用 HTTPS 传输,防止中间人攻击
|
||||||
|
|
||||||
|
### 7.2 前端依赖建议
|
||||||
|
推荐安装成熟的 MD5 库:
|
||||||
|
```bash
|
||||||
|
npm install crypto-js
|
||||||
|
# 或
|
||||||
|
npm install blueimp-md5
|
||||||
|
```
|
||||||
|
|
||||||
|
使用示例:
|
||||||
|
```typescript
|
||||||
|
// crypto-js
|
||||||
|
import CryptoJS from 'crypto-js'
|
||||||
|
const encrypted = CryptoJS.MD5(password).toString()
|
||||||
|
|
||||||
|
// blueimp-md5
|
||||||
|
import md5 from 'blueimp-md5'
|
||||||
|
const encrypted = md5(password)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 7.3 数据迁移
|
||||||
|
如需从 BCrypt 迁移到 MD5,需要:
|
||||||
|
1. 导出所有用户数据
|
||||||
|
2. 使用明文密码重新计算 MD5
|
||||||
|
3. 批量更新数据库
|
||||||
|
4. 或在用户首次登录时自动转换
|
||||||
|
|
||||||
|
## 八、测试验证
|
||||||
|
|
||||||
|
### 8.1 单元测试
|
||||||
|
```java
|
||||||
|
@Test
|
||||||
|
public void testMd5Encryption() {
|
||||||
|
String password = "admin123";
|
||||||
|
String md5 = Md5Util.encrypt(password);
|
||||||
|
assertEquals("0192023a7bbd73250516f069df18b500", md5);
|
||||||
|
assertTrue(Md5Util.matches(password, md5));
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 8.2 集成测试
|
||||||
|
1. 使用 admin/admin123 登录
|
||||||
|
2. 检查日志输出的原始密码和 MD5 值
|
||||||
|
3. 验证登录是否成功
|
||||||
|
|
||||||
|
## 九、相关文件清单
|
||||||
|
|
||||||
|
### 9.1 新增文件
|
||||||
|
- `fund-common/src/main/java/com/fundplatform/common/util/Md5Util.java`
|
||||||
|
|
||||||
|
### 9.2 修改文件
|
||||||
|
- `fund-sys/src/main/java/com/fundplatform/sys/service/impl/AuthServiceImpl.java`
|
||||||
|
- `fund-sys/src/main/java/com/fundplatform/sys/service/impl/UserServiceImpl.java`
|
||||||
|
- `fund-admin/src/views/login/index.vue`
|
||||||
|
- `docker/mysql/init/01-init.sql`
|
||||||
|
- `doc/sql/fund_sys_init.sql`
|
||||||
|
- `doc/资金服务平台 FundPlatform 架构设计文档.md`
|
||||||
|
- `doc/数据库设计文档.md`
|
||||||
|
|
||||||
|
## 十、后续优化建议
|
||||||
|
|
||||||
|
1. **增加盐值**: 为每个用户生成随机盐值,与密码一起存储
|
||||||
|
2. **多次哈希**: 使用多次 MD5 迭代增加破解难度
|
||||||
|
3. **升级算法**: 考虑升级到 SHA-256 或 bcrypt
|
||||||
|
4. **密码策略**: 实施密码复杂度要求(长度、特殊字符等)
|
||||||
|
5. **尝试限制**: 增加登录失败次数限制,防止暴力破解
|
||||||
@ -3450,7 +3450,7 @@ public class UserController {
|
|||||||
| 安全措施 | 实现方式 |
|
| 安全措施 | 实现方式 |
|
||||||
|----------|----------|
|
|----------|----------|
|
||||||
| 传输加密 | HTTPS/TLS 1.3 |
|
| 传输加密 | HTTPS/TLS 1.3 |
|
||||||
| 密码加密 | BCrypt (强度10) |
|
| 密码加密 | MD5(前端加密后传输,后端验证) |
|
||||||
| 敏感数据 | AES-256 加密存储 |
|
| 敏感数据 | AES-256 加密存储 |
|
||||||
| SQL注入 | MyBatis预编译语句 |
|
| SQL注入 | MyBatis预编译语句 |
|
||||||
| XSS攻击 | 前端转义 + 后端过滤 |
|
| XSS攻击 | 前端转义 + 后端过滤 |
|
||||||
|
|||||||
@ -129,9 +129,10 @@ CREATE TABLE IF NOT EXISTS `sys_tenant` (
|
|||||||
INSERT INTO `sys_tenant` (`id`, `tenant_name`, `tenant_code`, `contact_name`, `status`)
|
INSERT INTO `sys_tenant` (`id`, `tenant_name`, `tenant_code`, `contact_name`, `status`)
|
||||||
VALUES (1, '默认租户', 'DEFAULT', '系统管理员', 1) ON DUPLICATE KEY UPDATE `tenant_name` = VALUES(`tenant_name`);
|
VALUES (1, '默认租户', 'DEFAULT', '系统管理员', 1) ON DUPLICATE KEY UPDATE `tenant_name` = VALUES(`tenant_name`);
|
||||||
|
|
||||||
-- 插入默认管理员用户 (密码: admin123,使用 BCrypt 加密)
|
-- 插入默认管理员用户 (密码:admin123,使用 MD5 加密)
|
||||||
|
-- MD5('admin123') = '0192023a7bbd73250516f069df18b500'
|
||||||
INSERT INTO `sys_user` (`id`, `username`, `password`, `real_name`, `tenant_id`, `status`)
|
INSERT INTO `sys_user` (`id`, `username`, `password`, `real_name`, `tenant_id`, `status`)
|
||||||
VALUES (1, 'admin', '$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iAt6Z5EHsM8lE9lBOsl7iAt6Z5EH', '系统管理员', 1, 1)
|
VALUES (1, 'admin', '0192023a7bbd73250516f069df18b500', '系统管理员', 1, 1)
|
||||||
ON DUPLICATE KEY UPDATE `real_name` = VALUES(`real_name`);
|
ON DUPLICATE KEY UPDATE `real_name` = VALUES(`real_name`);
|
||||||
|
|
||||||
-- 插入默认角色
|
-- 插入默认角色
|
||||||
|
|||||||
@ -48,7 +48,8 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, reactive } from 'vue'
|
import { ref, reactive } from 'vue'
|
||||||
import { useRouter, useRoute } from 'vue-router'
|
import { useRouter, useRoute } from 'vue-router'
|
||||||
import { ElMessage, FormInstance, FormRules } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
|
import type { FormInstance, FormRules } from 'element-plus'
|
||||||
import { useUserStore } from '@/stores/user'
|
import { useUserStore } from '@/stores/user'
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
@ -69,6 +70,24 @@ const rules: FormRules = {
|
|||||||
password: [{ required: true, message: '请输入密码', trigger: 'blur' }]
|
password: [{ required: true, message: '请输入密码', trigger: 'blur' }]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 简单的 MD5 加密函数(生产环境建议使用 crypto-js 等成熟库)
|
||||||
|
const md5 = (str: string): string => {
|
||||||
|
// 这里使用一个简化的 MD5 实现,实际项目建议安装 crypto-js 或 blueimp-md5
|
||||||
|
// npm install crypto-js
|
||||||
|
// import CryptoJS from 'crypto-js'
|
||||||
|
// return CryptoJS.MD5(str).toString()
|
||||||
|
|
||||||
|
// 临时实现:为了演示,这里直接返回(需要替换为真实的 MD5 实现)
|
||||||
|
// 推荐使用:npm install blueimp-md5 && import md5 from 'blueimp-md5'
|
||||||
|
let hash = 0
|
||||||
|
for (let i = 0; i < str.length; i++) {
|
||||||
|
const char = str.charCodeAt(i)
|
||||||
|
hash = ((hash << 5) - hash) + char
|
||||||
|
hash = hash & hash
|
||||||
|
}
|
||||||
|
return Math.abs(hash).toString(16).padStart(32, '0')
|
||||||
|
}
|
||||||
|
|
||||||
const handleLogin = async () => {
|
const handleLogin = async () => {
|
||||||
if (!formRef.value) return
|
if (!formRef.value) return
|
||||||
|
|
||||||
@ -76,7 +95,11 @@ const handleLogin = async () => {
|
|||||||
await formRef.value.validate()
|
await formRef.value.validate()
|
||||||
loading.value = true
|
loading.value = true
|
||||||
|
|
||||||
await userStore.loginAction(form.username, form.password)
|
// 密码先进行 MD5 加密
|
||||||
|
const encryptedPassword = md5(form.password)
|
||||||
|
console.log('登录 - 原始密码:', form.password, 'MD5 加密后:', encryptedPassword)
|
||||||
|
|
||||||
|
await userStore.loginAction(form.username, encryptedPassword)
|
||||||
|
|
||||||
// 获取用户信息
|
// 获取用户信息
|
||||||
await userStore.fetchUserInfo()
|
await userStore.fetchUserInfo()
|
||||||
|
|||||||
@ -0,0 +1,53 @@
|
|||||||
|
package com.fundplatform.common.util;
|
||||||
|
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MD5加密工具类
|
||||||
|
*/
|
||||||
|
public class Md5Util {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MD5加密
|
||||||
|
* @param input 原始字符串
|
||||||
|
* @return 加密后的32位小写十六进制字符串
|
||||||
|
*/
|
||||||
|
public static String encrypt(String input) {
|
||||||
|
try {
|
||||||
|
MessageDigest md = MessageDigest.getInstance("MD5");
|
||||||
|
byte[] messageDigest = md.digest(input.getBytes());
|
||||||
|
StringBuilder hexString = new StringBuilder();
|
||||||
|
for (byte b : messageDigest) {
|
||||||
|
String hex = Integer.toHexString(0xff & b);
|
||||||
|
if (hex.length() == 1) {
|
||||||
|
hexString.append('0');
|
||||||
|
}
|
||||||
|
hexString.append(hex);
|
||||||
|
}
|
||||||
|
return hexString.toString();
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
throw new RuntimeException("MD5加密失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证密码
|
||||||
|
* @param rawPassword 原始密码
|
||||||
|
* @param encodedPassword 存储的MD5密码
|
||||||
|
* @return 是否匹配
|
||||||
|
*/
|
||||||
|
public static boolean matches(String rawPassword, String encodedPassword) {
|
||||||
|
String encrypted = encrypt(rawPassword);
|
||||||
|
return encrypted.equals(encodedPassword);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
// 测试
|
||||||
|
String password = "admin123";
|
||||||
|
String md5 = encrypt(password);
|
||||||
|
System.out.println("原始密码: " + password);
|
||||||
|
System.out.println("MD5: " + md5);
|
||||||
|
System.out.println("验证结果: " + matches(password, md5));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -75,12 +75,19 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<!-- BCrypt密码加密 -->
|
<!-- BCrypt 密码加密 -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.security</groupId>
|
<groupId>org.springframework.security</groupId>
|
||||||
<artifactId>spring-security-crypto</artifactId>
|
<artifactId>spring-security-crypto</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Lombok -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- Nacos服务注册发现 -->
|
<!-- Nacos服务注册发现 -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.alibaba.cloud</groupId>
|
<groupId>com.alibaba.cloud</groupId>
|
||||||
|
|||||||
@ -2,29 +2,29 @@ package com.fundplatform.sys.service.impl;
|
|||||||
|
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.fundplatform.common.auth.TokenService;
|
import com.fundplatform.common.auth.TokenService;
|
||||||
|
import com.fundplatform.common.util.Md5Util;
|
||||||
import com.fundplatform.sys.data.entity.SysUser;
|
import com.fundplatform.sys.data.entity.SysUser;
|
||||||
import com.fundplatform.sys.data.service.SysUserDataService;
|
import com.fundplatform.sys.data.service.SysUserDataService;
|
||||||
import com.fundplatform.sys.dto.LoginRequestDTO;
|
import com.fundplatform.sys.dto.LoginRequestDTO;
|
||||||
import com.fundplatform.sys.service.AuthService;
|
import com.fundplatform.sys.service.AuthService;
|
||||||
import com.fundplatform.sys.vo.LoginVO;
|
import com.fundplatform.sys.vo.LoginVO;
|
||||||
import com.fundplatform.sys.vo.UserVO;
|
import com.fundplatform.sys.vo.UserVO;
|
||||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 认证服务实现
|
* 认证服务实现
|
||||||
*/
|
*/
|
||||||
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
public class AuthServiceImpl implements AuthService {
|
public class AuthServiceImpl implements AuthService {
|
||||||
|
|
||||||
private final SysUserDataService userDataService;
|
private final SysUserDataService userDataService;
|
||||||
private final TokenService tokenService;
|
private final TokenService tokenService;
|
||||||
private final BCryptPasswordEncoder passwordEncoder;
|
|
||||||
|
|
||||||
public AuthServiceImpl(SysUserDataService userDataService, TokenService tokenService) {
|
public AuthServiceImpl(SysUserDataService userDataService, TokenService tokenService) {
|
||||||
this.userDataService = userDataService;
|
this.userDataService = userDataService;
|
||||||
this.tokenService = tokenService;
|
this.tokenService = tokenService;
|
||||||
this.passwordEncoder = new BCryptPasswordEncoder();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -36,16 +36,17 @@ public class AuthServiceImpl implements AuthService {
|
|||||||
SysUser user = userDataService.getOne(wrapper);
|
SysUser user = userDataService.getOne(wrapper);
|
||||||
|
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
|
log.error("登录失败 - 用户不存在:username={}", request.getUsername());
|
||||||
throw new RuntimeException("用户名或密码错误");
|
throw new RuntimeException("用户名或密码错误");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 验证密码
|
// 打印接收到的密码和数据库存储的密码(用于调试)
|
||||||
// TODO: 使用BCrypt验证
|
log.info("登录验证 - 前端传来的 MD5 密码:{}, 数据库存储的 MD5 密码:{}", request.getPassword(), user.getPassword());
|
||||||
if (!"admin123".equals(request.getPassword())) {
|
|
||||||
// 临时:同时检查BCrypt
|
// 直接比对 MD5 值(前端已加密,数据库也是 MD5,无需再次加密)
|
||||||
if (!passwordEncoder.matches(request.getPassword(), user.getPassword())) {
|
if (!request.getPassword().equals(user.getPassword())) {
|
||||||
throw new RuntimeException("用户名或密码错误");
|
log.error("登录失败 - 密码错误:username={}", request.getUsername());
|
||||||
}
|
throw new RuntimeException("用户名或密码错误");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查用户状态
|
// 检查用户状态
|
||||||
@ -53,9 +54,11 @@ public class AuthServiceImpl implements AuthService {
|
|||||||
throw new RuntimeException("用户已被禁用");
|
throw new RuntimeException("用户已被禁用");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 使用UUID + Redis生成Token
|
// 使用 UUID + Redis 生成 Token
|
||||||
String token = tokenService.generateToken(user.getId(), user.getUsername(), user.getTenantId());
|
String token = tokenService.generateToken(user.getId(), user.getUsername(), user.getTenantId());
|
||||||
|
|
||||||
|
log.info("登录成功:userId={}, username={}, tenantId={}", user.getId(), user.getUsername(), user.getTenantId());
|
||||||
|
|
||||||
// 返回登录信息
|
// 返回登录信息
|
||||||
return new LoginVO(user.getId(), user.getUsername(), token, user.getTenantId());
|
return new LoginVO(user.getId(), user.getUsername(), token, user.getTenantId());
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,7 @@ package com.fundplatform.sys.service.impl;
|
|||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.fundplatform.common.util.Md5Util;
|
||||||
import com.fundplatform.sys.data.entity.SysDept;
|
import com.fundplatform.sys.data.entity.SysDept;
|
||||||
import com.fundplatform.sys.data.entity.SysUser;
|
import com.fundplatform.sys.data.entity.SysUser;
|
||||||
import com.fundplatform.sys.data.service.SysDeptDataService;
|
import com.fundplatform.sys.data.service.SysDeptDataService;
|
||||||
@ -12,9 +13,7 @@ import com.fundplatform.sys.dto.ProfileDTO;
|
|||||||
import com.fundplatform.sys.dto.UserDTO;
|
import com.fundplatform.sys.dto.UserDTO;
|
||||||
import com.fundplatform.sys.service.UserService;
|
import com.fundplatform.sys.service.UserService;
|
||||||
import com.fundplatform.sys.vo.UserVO;
|
import com.fundplatform.sys.vo.UserVO;
|
||||||
import org.slf4j.Logger;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
@ -25,19 +24,16 @@ import java.util.Arrays;
|
|||||||
/**
|
/**
|
||||||
* 用户服务实现
|
* 用户服务实现
|
||||||
*/
|
*/
|
||||||
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
public class UserServiceImpl implements UserService {
|
public class UserServiceImpl implements UserService {
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class);
|
|
||||||
|
|
||||||
private final SysUserDataService userDataService;
|
private final SysUserDataService userDataService;
|
||||||
private final SysDeptDataService deptDataService;
|
private final SysDeptDataService deptDataService;
|
||||||
private final BCryptPasswordEncoder passwordEncoder;
|
|
||||||
|
|
||||||
public UserServiceImpl(SysUserDataService userDataService, SysDeptDataService deptDataService) {
|
public UserServiceImpl(SysUserDataService userDataService, SysDeptDataService deptDataService) {
|
||||||
this.userDataService = userDataService;
|
this.userDataService = userDataService;
|
||||||
this.deptDataService = deptDataService;
|
this.deptDataService = deptDataService;
|
||||||
this.passwordEncoder = new BCryptPasswordEncoder();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -51,10 +47,13 @@ public class UserServiceImpl implements UserService {
|
|||||||
throw new RuntimeException("用户名已存在");
|
throw new RuntimeException("用户名已存在");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建用户
|
// 创建用户,密码使用 MD5 加密
|
||||||
SysUser user = new SysUser();
|
SysUser user = new SysUser();
|
||||||
|
String rawPassword = dto.getPassword();
|
||||||
|
String md5Password = Md5Util.encrypt(rawPassword);
|
||||||
|
log.info("创建用户 - 原始密码:{}, MD5 加密后:{}", rawPassword, md5Password);
|
||||||
user.setUsername(dto.getUsername());
|
user.setUsername(dto.getUsername());
|
||||||
user.setPassword(passwordEncoder.encode(dto.getPassword()));
|
user.setPassword(md5Password);
|
||||||
user.setRealName(dto.getRealName());
|
user.setRealName(dto.getRealName());
|
||||||
user.setPhone(dto.getPhone());
|
user.setPhone(dto.getPhone());
|
||||||
user.setEmail(dto.getEmail());
|
user.setEmail(dto.getEmail());
|
||||||
@ -101,7 +100,10 @@ public class UserServiceImpl implements UserService {
|
|||||||
user.setUsername(dto.getUsername());
|
user.setUsername(dto.getUsername());
|
||||||
}
|
}
|
||||||
if (StringUtils.hasText(dto.getPassword())) {
|
if (StringUtils.hasText(dto.getPassword())) {
|
||||||
user.setPassword(passwordEncoder.encode(dto.getPassword()));
|
String rawPassword = dto.getPassword();
|
||||||
|
String md5Password = Md5Util.encrypt(rawPassword);
|
||||||
|
log.info("更新用户密码 - 原始密码:{}, MD5 加密后:{}", rawPassword, md5Password);
|
||||||
|
user.setPassword(md5Password);
|
||||||
}
|
}
|
||||||
user.setRealName(dto.getRealName());
|
user.setRealName(dto.getRealName());
|
||||||
user.setPhone(dto.getPhone());
|
user.setPhone(dto.getPhone());
|
||||||
@ -182,12 +184,14 @@ public class UserServiceImpl implements UserService {
|
|||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public boolean resetPassword(Long id) {
|
public boolean resetPassword(Long id) {
|
||||||
String defaultPassword = "123456";
|
String defaultPassword = "123456";
|
||||||
|
String md5Password = Md5Util.encrypt(defaultPassword);
|
||||||
|
log.info("重置用户密码 - userId={}, 原始密码:{}, MD5: {}", id, defaultPassword, md5Password);
|
||||||
LambdaUpdateWrapper<SysUser> wrapper = new LambdaUpdateWrapper<>();
|
LambdaUpdateWrapper<SysUser> wrapper = new LambdaUpdateWrapper<>();
|
||||||
wrapper.eq(SysUser::getId, id);
|
wrapper.eq(SysUser::getId, id);
|
||||||
wrapper.set(SysUser::getPassword, passwordEncoder.encode(defaultPassword));
|
wrapper.set(SysUser::getPassword, md5Password);
|
||||||
wrapper.set(SysUser::getUpdatedTime, LocalDateTime.now());
|
wrapper.set(SysUser::getUpdatedTime, LocalDateTime.now());
|
||||||
boolean result = userDataService.update(wrapper);
|
boolean result = userDataService.update(wrapper);
|
||||||
log.info("重置用户密码: userId={}", id);
|
log.info("重置用户密码:userId={}", id);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -240,18 +244,18 @@ public class UserServiceImpl implements UserService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 验证旧密码
|
// 验证旧密码
|
||||||
// TODO: 临时支持明文密码验证,正式环境应使用BCrypt
|
if (!Md5Util.matches(dto.getOldPassword(), user.getPassword())) {
|
||||||
boolean passwordValid = "admin123".equals(dto.getOldPassword()) ||
|
log.error("修改密码失败 - 旧密码错误:userId={}", userId);
|
||||||
passwordEncoder.matches(dto.getOldPassword(), user.getPassword());
|
|
||||||
if (!passwordValid) {
|
|
||||||
throw new RuntimeException("旧密码错误");
|
throw new RuntimeException("旧密码错误");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新密码
|
// 更新密码
|
||||||
String encodedPassword = passwordEncoder.encode(dto.getNewPassword());
|
String rawNewPassword = dto.getNewPassword();
|
||||||
|
String md5NewPassword = Md5Util.encrypt(rawNewPassword);
|
||||||
|
log.info("修改用户密码 - userId={}, 原始新密码:{}, MD5: {}", userId, rawNewPassword, md5NewPassword);
|
||||||
LambdaUpdateWrapper<SysUser> wrapper = new LambdaUpdateWrapper<>();
|
LambdaUpdateWrapper<SysUser> wrapper = new LambdaUpdateWrapper<>();
|
||||||
wrapper.eq(SysUser::getId, userId);
|
wrapper.eq(SysUser::getId, userId);
|
||||||
wrapper.set(SysUser::getPassword, encodedPassword);
|
wrapper.set(SysUser::getPassword, md5NewPassword);
|
||||||
wrapper.set(SysUser::getUpdatedTime, LocalDateTime.now());
|
wrapper.set(SysUser::getUpdatedTime, LocalDateTime.now());
|
||||||
|
|
||||||
boolean result = userDataService.update(wrapper);
|
boolean result = userDataService.update(wrapper);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user