Files
ClassManager/backend/utils/security.py
2026-04-07 17:07:13 +08:00

131 lines
3.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ===========================================
# 班级操行分管理系统 - 后端服务
#
# 开发者: Canglan
# 联系方式: admin@sea-studio.top
# 版权归属: Sea Network Technology Studio
# 许可证: MIT License
#
# 版权所有 © Sea Network Technology Studio
# ===========================================
import hashlib
import secrets
import re
from config import settings
class SecurityUtils:
"""安全工具类"""
@staticmethod
def sha1_md5_password(password: str) -> str:
"""
双重加密sha1 + md5
流程:原始密码 -> sha1 -> 加盐 -> md5
"""
# 第一层SHA1
sha1_hash = hashlib.sha1(password.encode('utf-8')).hexdigest()
# 加盐
salted = sha1_hash + settings.PASSWORD_SALT
# 第二层MD5
md5_hash = hashlib.md5(salted.encode('utf-8')).hexdigest()
return md5_hash
@staticmethod
def verify_password(plain_password: str, hashed_password: str) -> bool:
"""验证密码"""
return SecurityUtils.sha1_md5_password(plain_password) == hashed_password
@staticmethod
def generate_random_password(length: int = 8) -> str:
"""生成随机密码"""
alphabet = 'abcdefghijkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789'
return ''.join(secrets.choice(alphabet) for _ in range(length))
@staticmethod
def validate_password_strength(password: str) -> tuple:
"""
验证密码强度
返回: (是否有效, 错误信息)
"""
if len(password) < 6:
return False, "密码长度至少6位"
if len(password) > 20:
return False, "密码长度不能超过20位"
# 检查是否包含至少一个数字
if not any(c.isdigit() for c in password):
return False, "密码必须包含至少一个数字"
# 检查是否包含至少一个字母
if not any(c.isalpha() for c in password):
return False, "密码必须包含至少一个字母"
return True, ""
@staticmethod
def sanitize_string(value: str, max_length: int = 255) -> str:
"""
清理字符串输入
- 去除首尾空格
- 限制长度
- 转义特殊字符
"""
if not value:
return ""
# 去除首尾空格
value = value.strip()
# 限制长度
if len(value) > max_length:
value = value[:max_length]
# 转义HTML特殊字符防止XSS
html_chars = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
"'": '&#x27;',
'/': '&#x2F;'
}
for char, escape in html_chars.items():
value = value.replace(char, escape)
return value
@staticmethod
def validate_student_no(student_no: str) -> bool:
"""验证学号格式(数字+字母长度4-20"""
if not student_no:
return False
if len(student_no) < 4 or len(student_no) > 20:
return False
# 字母数字组合
return student_no.isalnum()
@staticmethod
def validate_phone(phone: str) -> bool:
"""验证手机号格式(中国手机号)"""
if not phone:
return False
pattern = r'^1[3-9]\d{9}$'
return bool(re.match(pattern, phone))
@staticmethod
def validate_points_change(points: int, max_abs: int = 100) -> tuple:
"""
验证分值变动
返回: (是否有效, 错误信息)
"""
if points == 0:
return False, "分值不能为0"
if abs(points) > max_abs:
return f"单次分值变动不能超过{max_abs}"
return True, ""
# 单例导出
security = SecurityUtils()