blob: 2d3f7da1091eeaa89d5011bcd30c3791ea18cb67 [file] [log] [blame]
Raverafc93da2025-06-15 18:12:49 +08001# filepath: /home/ronghanji/api/API-TRM/rhj/backend/app/models/email_verification.py
2from . import Base
3from sqlalchemy import (
4 Column, Integer, String, Boolean, TIMESTAMP, text, ForeignKey
5)
6from sqlalchemy.orm import relationship
7from datetime import datetime, timedelta
8import secrets
9import string
10import hashlib
11import pytz
12
13
14class EmailVerification(Base):
15 __tablename__ = 'email_verifications'
16
17 id = Column(Integer, primary_key=True, autoincrement=True, comment='验证记录ID')
18 email = Column(String(100), nullable=False, comment='邮箱地址')
19 code = Column(String(255), nullable=False, comment='验证码(加密存储)')
20 type = Column(String(50), nullable=False, comment='验证类型:register, reset_password, email_change')
21 user_id = Column(Integer, ForeignKey('users.id'), nullable=True, comment='关联用户ID')
22 is_verified = Column(Boolean, nullable=False, default=False, comment='是否已验证')
23 expires_at = Column(TIMESTAMP, nullable=False, comment='过期时间')
24 created_at = Column(
25 TIMESTAMP,
26 nullable=False,
27 server_default=text('CURRENT_TIMESTAMP'),
28 comment='创建时间'
29 )
30 verified_at = Column(TIMESTAMP, nullable=True, comment='验证时间')
31
32 # 关联用户表
33 user = relationship("User", back_populates="email_verifications")
34
35 def __init__(self, email, verification_type, user_id=None, expires_minutes=15):
36 """初始化邮箱验证记录
37
38 Args:
39 email: 邮箱地址
40 verification_type: 验证类型
41 user_id: 用户ID(可选)
42 expires_minutes: 过期时间(分钟)
43 """
44 self.email = email
45 self.type = verification_type
46 self.user_id = user_id
47 self.is_verified = False
48
49 # 使用中国时区时间,确保与数据库时间一致
50 china_tz = pytz.timezone('Asia/Shanghai')
51 current_time = datetime.now(china_tz).replace(tzinfo=None)
52 self.expires_at = current_time + timedelta(minutes=expires_minutes)
53
54 # 生成并加密验证码
55 raw_code = self._generate_code()
56 self.code = self._hash_code(raw_code)
57 self._raw_code = raw_code # 临时存储原始验证码用于发送邮件
58
59 @classmethod
60 def create_verification(cls, email, verification_type, user_id=None, expires_minutes=15):
61 """创建验证记录
62
63 Args:
64 email: 邮箱地址
65 verification_type: 验证类型
66 user_id: 用户ID(可选)
67 expires_minutes: 过期时间(分钟)
68
69 Returns:
70 EmailVerification: 验证记录实例
71 """
72 return cls(
73 email=email,
74 verification_type=verification_type,
75 user_id=user_id,
76 expires_minutes=expires_minutes
77 )
78
79 def _generate_code(self, length=6):
80 """生成随机验证码
81
82 Args:
83 length: 验证码长度
84
85 Returns:
86 str: 验证码
87 """
88 characters = string.digits
89 return ''.join(secrets.choice(characters) for _ in range(length))
90
91 def _hash_code(self, code):
92 """对验证码进行哈希加密
93
94 Args:
95 code: 原始验证码
96
97 Returns:
98 str: 加密后的验证码
99 """
100 return hashlib.sha256(code.encode()).hexdigest()
101
102 def verify(self, input_code):
103 """验证验证码
104
105 Args:
106 input_code: 用户输入的验证码
107
108 Returns:
109 bool: 验证是否成功
110 """
111 if self.is_verified:
112 return False
113
114 if self.is_expired():
115 return False
116
117 hashed_input = self._hash_code(input_code)
118 if hashed_input == self.code:
119 # 使用中国时区时间设置验证时间
120 china_tz = pytz.timezone('Asia/Shanghai')
121 self.verified_at = datetime.now(china_tz).replace(tzinfo=None)
122 self.is_verified = True
123 return True
124
125 return False
126
127 def verify_hashed(self, hashed_code):
128 """验证已经加密的验证码
129
130 Args:
131 hashed_code: 已经加密的验证码
132
133 Returns:
134 bool: 验证是否成功
135 """
136 if self.is_verified:
137 return False
138
139 if self.is_expired():
140 return False
141
142 # 直接比较加密后的验证码
143 if hashed_code == self.code:
144 # 使用中国时区时间设置验证时间
145 china_tz = pytz.timezone('Asia/Shanghai')
146 self.verified_at = datetime.now(china_tz).replace(tzinfo=None)
147 self.is_verified = True
148 return True
149
150 return False
151
152 def is_expired(self):
153 """检查是否已过期
154
155 Returns:
156 bool: 是否已过期
157 """
158 # 使用中国时区时间进行比较
159 china_tz = pytz.timezone('Asia/Shanghai')
160 current_time = datetime.now(china_tz).replace(tzinfo=None)
161 return current_time > self.expires_at
162
163 def get_raw_code(self):
164 """获取原始验证码(仅在创建时可用)
165
166 Returns:
167 str: 原始验证码
168 """
169 return getattr(self, '_raw_code', None)
170
171 def to_dict(self):
172 """转换为字典格式
173
174 Returns:
175 dict: 对象字典表示
176 """
177 return {
178 'id': self.id,
179 'email': self.email,
180 'type': self.type,
181 'user_id': self.user_id,
182 'is_verified': self.is_verified,
183 'expires_at': self.expires_at.isoformat() if self.expires_at else None,
184 'created_at': self.created_at.isoformat() if self.created_at else None,
185 'verified_at': self.verified_at.isoformat() if self.verified_at else None
186 }
187
188 def __repr__(self):
189 return f"<EmailVerification(id={self.id}, email='{self.email}', type='{self.type}', verified={self.is_verified})>"