feat(passkey): 添加PassKey支持并优化双重验证登录逻辑

This commit is contained in:
PKC278
2025-12-23 13:53:54 +08:00
parent abd9733e7f
commit 0c6cfc5020
10 changed files with 957 additions and 51 deletions

View File

@@ -52,7 +52,10 @@ class UserChain(ChainBase):
success, user_or_message = self.password_authenticate(credentials=credentials)
if success:
# 如果用户启用了二次验证码,则进一步验证
if not self._verify_mfa(user_or_message, credentials.mfa_code):
mfa_result = self._verify_mfa(user_or_message, credentials.mfa_code)
if mfa_result == "MFA_REQUIRED":
return False, "MFA_REQUIRED"
elif not mfa_result:
return False, PASSWORD_INVALID_CREDENTIALS_MESSAGE
logger.info(f"用户 {username} 通过密码认证成功")
return True, user_or_message
@@ -63,7 +66,10 @@ class UserChain(ChainBase):
aux_success, aux_user_or_message = self.auxiliary_authenticate(credentials=credentials)
if aux_success:
# 辅助认证成功后再验证二次验证码
if not self._verify_mfa(aux_user_or_message, credentials.mfa_code):
mfa_result = self._verify_mfa(aux_user_or_message, credentials.mfa_code)
if mfa_result == "MFA_REQUIRED":
return False, "MFA_REQUIRED"
elif not mfa_result:
return False, PASSWORD_INVALID_CREDENTIALS_MESSAGE
return True, aux_user_or_message
else:
@@ -159,22 +165,37 @@ class UserChain(ChainBase):
return False, PASSWORD_INVALID_CREDENTIALS_MESSAGE
@staticmethod
def _verify_mfa(user: User, mfa_code: Optional[str]) -> bool:
def _verify_mfa(user: User, mfa_code: Optional[str]) -> Union[bool, str]:
"""
验证 MFA二次验证码
检查用户是否启用了 OTP 或 PassKey如果启用了任何一种都需要提供验证
:param user: 用户对象
:param mfa_code: 二次验证码
:return: 如果验证成功返回 True否则返回 False
:param mfa_code: 二次验证码如果提供了则验证OTP
:return:
- 如果验证成功返回 True
- 如果需要MFA但未提供返回 "MFA_REQUIRED"
- 如果MFA验证失败返回 False
"""
if not user.is_otp:
# 检查用户是否有PassKey
from app.db.models.passkey import PassKey
has_passkey = bool(PassKey().get_by_user_id(db=None, user_id=user.id))
# 如果用户既没有启用OTP也没有PassKey直接通过
if not user.is_otp and not has_passkey:
return True
# 如果用户启用了OTP或PassKey但没有提供验证码需要进行二次验证
if not mfa_code:
logger.info(f"用户 {user.name} 缺少 MFA 认证码")
return False
if not OtpUtils.check(str(user.otp_secret), mfa_code):
logger.info(f"用户 {user.name} 的 MFA 认证失败")
return False
logger.info(f"用户 {user.name} 已启用双重验证OTP: {user.is_otp}, PassKey: {has_passkey}),需要提供验证码")
return "MFA_REQUIRED"
# 如果提供了验证码验证OTP
if user.is_otp:
if not OtpUtils.check(str(user.otp_secret), mfa_code):
logger.info(f"用户 {user.name} 的 MFA 认证失败")
return False
return True
def _process_auth_success(self, username: str, credentials: AuthCredentials) -> bool: