feat: 多班级版 v2.0 - Go后端重写 + 43轮代码审查
- 后端从 Python FastAPI 重写为 Go Gin(端口 56789) - 多班级完全隔离 - 超级管理员独立登录 - 课代表作业管理、排行榜分项排行 - 角色加减分上下限可配置 - 家长改密功能(可开关) - 周度/月度重置功能 - MySQL 5.7 兼容 - 43轮代码审查+全部修复 - Apache 2.0 许可证
This commit is contained in:
110
backend-go/pkg/crypto/password.go
Normal file
110
backend-go/pkg/crypto/password.go
Normal file
@@ -0,0 +1,110 @@
|
||||
// ===========================================
|
||||
// 多班级版班级管理系统 - Go 后端
|
||||
//
|
||||
// 开发者: Canglan
|
||||
// 联系方式: admin@sea-studio.top
|
||||
// 版权归属: Sea Network Technology Studio
|
||||
// 许可证: Apache License 2.0
|
||||
//
|
||||
// 版权所有 © Sea Network Technology Studio
|
||||
// ===========================================
|
||||
|
||||
package crypto
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"crypto/rand"
|
||||
"crypto/sha1"
|
||||
"crypto/subtle"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
// HashPassword 密码哈希(与 Python 版完全兼容)
|
||||
// 算法: MD5(SHA1(password) + salt)
|
||||
// Python 参考: backend/utils/security.py -> sha1_md5_password()
|
||||
// 已知弱算法:MD5 和 SHA1 均不适合密码哈希场景,保留此实现仅为兼容 Python 版数据。
|
||||
// 后续迁移计划:迁移到 bcrypt/scrypt/argon2,并提供兼容层逐步过渡。
|
||||
func HashPassword(password string, salt string) string {
|
||||
// 第一层: SHA1(password)
|
||||
sha1Hash := sha1.Sum([]byte(password))
|
||||
sha1Hex := hex.EncodeToString(sha1Hash[:])
|
||||
|
||||
// 加盐: SHA1_hex + salt
|
||||
salted := sha1Hex + salt
|
||||
|
||||
// 第二层: MD5(salted)
|
||||
md5Hash := md5.Sum([]byte(salted))
|
||||
return hex.EncodeToString(md5Hash[:])
|
||||
}
|
||||
|
||||
// VerifyPassword 验证密码(使用常量时间比较,防止时序攻击)
|
||||
func VerifyPassword(plainPassword, hashedPassword, salt string) bool {
|
||||
computed := HashPassword(plainPassword, salt)
|
||||
return subtle.ConstantTimeCompare([]byte(computed), []byte(hashedPassword)) == 1
|
||||
}
|
||||
|
||||
// GenerateRandomPassword 生成随机密码
|
||||
// 与 Python 版 SecurityUtils.generate_random_password() 兼容
|
||||
func GenerateRandomPassword(length int) (string, error) {
|
||||
alphabet := "abcdefghijkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789"
|
||||
result := make([]byte, length)
|
||||
for i := range result {
|
||||
n, err := rand.Int(rand.Reader, big.NewInt(int64(len(alphabet))))
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("生成随机密码失败: %w", err)
|
||||
}
|
||||
result[i] = alphabet[n.Int64()]
|
||||
}
|
||||
return string(result), nil
|
||||
}
|
||||
|
||||
// ValidatePasswordStrength 验证密码强度
|
||||
// 要求: 大小写字母、数字、特殊符号至少包含 3 种,长度 6-20
|
||||
func ValidatePasswordStrength(password string) (bool, string) {
|
||||
if len(password) < 6 {
|
||||
return false, "密码长度至少6位"
|
||||
}
|
||||
if len(password) > 20 {
|
||||
return false, "密码长度不能超过20位"
|
||||
}
|
||||
|
||||
hasUpper := false
|
||||
hasLower := false
|
||||
hasDigit := false
|
||||
hasSpecial := false
|
||||
|
||||
for _, c := range password {
|
||||
switch {
|
||||
case c >= 'A' && c <= 'Z':
|
||||
hasUpper = true
|
||||
case c >= 'a' && c <= 'z':
|
||||
hasLower = true
|
||||
case c >= '0' && c <= '9':
|
||||
hasDigit = true
|
||||
default:
|
||||
hasSpecial = true
|
||||
}
|
||||
}
|
||||
|
||||
charTypes := 0
|
||||
if hasUpper {
|
||||
charTypes++
|
||||
}
|
||||
if hasLower {
|
||||
charTypes++
|
||||
}
|
||||
if hasDigit {
|
||||
charTypes++
|
||||
}
|
||||
if hasSpecial {
|
||||
charTypes++
|
||||
}
|
||||
|
||||
if charTypes < 3 {
|
||||
return false, "密码必须包含大写字母、小写字母、数字、特殊符号中的至少3种"
|
||||
}
|
||||
|
||||
return true, ""
|
||||
}
|
||||
Reference in New Issue
Block a user