用戶忘記密碼 → 後端生成 6 位隨機臨時密碼 → 經由即時通/簡訊/微信發送 → 同步更新資料庫密碼(存儲 MD5 密文) → 用戶登入後強制修改密碼。
核心安全要求:
public final class Md5Utils {
private Md5Utils() {} // 工具類禁止實例化
/**
* 計算字串的 MD5 雜湊值(32 位小寫十六進制)
* @param input 待加密明文
* @return 32 位十六進制字串,輸入為 null 返回空串
*/
public static String encode(String input) {
if (input == null) return "";
try {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] digest = md.digest(input.getBytes(StandardCharsets.UTF_8));
// 位元組陣列轉十六進制字串
StringBuilder sb = new StringBuilder(32);
for (byte b : digest) {
int v = b & 0xFF; // 無符號位元組值
if (v < 0x10) sb.append('0'); // 高位補零
sb.append(Integer.toHexString(v));
}
return sb.toString();
} catch (NoSuchAlgorithmException e) {
throw new IllegalStateException("JVM 缺少 MD5 實現", e);
}
}
/**
* 驗證明文與雜湊值是否匹配(防時序攻擊用 MessageDigest.isEqual)
*/
public static boolean matches(String raw, String hash) {
if (raw == null || hash == null) return false;
String calculated = encode(raw);
return MessageDigest.isEqual(calculated.getBytes(StandardCharsets.UTF_8),
hash.getBytes(StandardCharsets.UTF_8));
}
}
@RestController
@RequestMapping("/api/auth")
public class AuthController {
@Autowired private UserService userService;
@Autowired private MessageService messageService;
@PostMapping("/reset-password")
public Result<Void> resetPassword(@RequestParam Long userId) {
// 1. 生成 6 位隨機數字密碼
String tempPassword = String.format("%06d", new Random().nextInt(1_000_000));
// 2. 計算 MD5 並更新資料庫
String passwordHash = Md5Utils.encode(tempPassword);
if (userService.updatePassword(userId, passwordHash) == 0) {
throw new BusinessException("臨時密碼生成失敗");
}
// 3. 發送通知(即時通/簡訊/郵件)
String xml = buildNotificationXml(userId, tempPassword);
messageService.sendImMessage(xml);
return Result.success();
}
private String buildNotificationXml(Long userId, String tempPassword) {
// 實際專案建議使用 JAXB 或模板引擎生成 XML
return "<SendMessage>" +
"<UserId>" + userId + "</UserId>" +
"<MessageTxt>您的臨時密碼是:" + tempPassword + ",請盡快登入修改。</MessageTxt>" +
"<SystemName>後台管理系統</SystemName>" +
"<Type>即時通</Type>" +
"</SendMessage>";
}
}
本文示範 MD5 僅為教學演示臨時密碼流程。生產環境用戶長期密碼必須使用慢速雜湊演算法:
| 演算法 | 特點 | 推薦參數 |
|---|---|---|
| BCrypt | 自帶 Salt、可調成本因子、廣泛支援 | Cost 10-12(~100-300ms) |
| Argon2id | 記憶體硬化、抗 GPU/ASIC、現代標準 | 時間 3、記憶體 64MB、並行 4 |
| PBKDF2 | 標準化、FIPS 認證、Java 內建 | 迭代 100,000+、SHA-256 |
| scrypt | 記憶體硬化、較早期方案 | N=16384, r=8, p=1 |
@Configuration
public class SecurityConfig {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(12); // Cost 12
}
}
@Service
public class UserServiceImpl implements UserService {
@Autowired private PasswordEncoder encoder;
public void updatePassword(Long userId, String rawPassword) {
String hash = encoder.encode(rawPassword); // 自動生成 Salt、雜湊
userDao.updatePasswordHash(userId, hash);
}
public boolean verifyPassword(Long userId, String rawPassword) {
String hash = userDao.getPasswordHash(userId);
return encoder.matches(rawPassword, hash); // 驗證
}
}
記住:MD5 適合校驗檔案完整性、非安全場景雜湊;密碼存儲請用專門的慢速雜湊演算法。