修正安全码验证后重新查看的提示与注释
Some checks are pending
Security Checks / security (push) Waiting to run

This commit is contained in:
smail 2026-09-27 17:50:03 +08:00
parent 0a81d70ba3
commit cea2269249
7 changed files with 9 additions and 8 deletions

View File

@ -300,7 +300,7 @@ func SetSecurityQuestion(ctx *context.Context, w http.ResponseWriter, req *http.
response.NewSuccessResponse(map[string]any{"configured": true}).FPrint(w)
}
// GenerateRecoveryCodes 生成一组只显示一次的离线恢复码。
// GenerateRecoveryCodes 生成一组离线恢复码,未使用的有效恢复码可在安全验证后再次查看。
func GenerateRecoveryCodes(ctx *context.Context, w http.ResponseWriter, req *http.Request) {
if ctx == nil || ctx.UserID <= 0 {
writeSecurityError(w, response.NeedLogin, "请先登录")

View File

@ -140,7 +140,7 @@ func RevealManagedRecoveryCodes(ctx *context.Context, w http.ResponseWriter, req
response.NewSuccessResponse(map[string]any{"user_id": target.ID, "codes": codes, "revealed": true}).FPrint(w)
}
// GenerateManagedRecoveryCodes 为目标用户生成只显示一次的安全码。
// GenerateManagedRecoveryCodes 为目标用户生成安全码,有管理权限的管理员可在安全验证后再次查看有效安全码。
func GenerateManagedRecoveryCodes(ctx *context.Context, w http.ResponseWriter, req *http.Request) {
var input managedUserSecurityRequest
if err := decodeUserRequest(w, req, &input); err != nil {

View File

@ -15,7 +15,8 @@ type SecurityQuestion struct {
func (SecurityQuestion) TableName() string { return "security_question" }
// RecoveryCode 保存一次性离线恢复码的 Argon2id 哈希,UsedAt 非空表示已经消费或撤销。
// RecoveryCode 保存一次性离线恢复码的 Argon2id 哈希和用于安全验证后查看的密文。
// UsedAt 非空表示已经消费或撤销,此时密文会被清除,不再允许查看或使用。
type RecoveryCode struct {
ID int `xorm:"id bigint unsigned not null pk autoincr" json:"-"`
UserID int `xorm:"user_id bigint not null index" json:"-"`

View File

@ -143,7 +143,7 @@ func (s *Service) VerifySecurityQuestion(userID int, answer string) (bool, error
return password.Check(item.AnswerHash, answer)
}
// GenerateRecoveryCodes 撤销旧码并生成一组只返回一次的离线恢复码。
// GenerateRecoveryCodes 撤销旧码并生成一组离线恢复码,保存哈希和受保护的密文以支持安全验证后再次查看。
func (s *Service) GenerateRecoveryCodes(userID int, count int) ([]string, error) {
return s.GenerateRecoveryCodesContext(context.Background(), userID, count)
}

View File

@ -92,7 +92,7 @@ const generateRecoveryCodes = async () => {
generatedCodes.value = response.data.codes
globalStatus.userInfos.recoveryCodesConfigured = true
globalStatus.userInfos.showRecoverySetupPrompt = false
ElMessage.success("恢复码已生成,请仅保存这一次显示的内容")
ElMessage.success("恢复码已生成,请妥善保存;可在安全设置中验证本人密码后再次查看有效恢复码")
} catch (error) {
ElMessage.error(error?.message || "离线恢复码生成失败,请稍后重试")
} finally {

View File

@ -258,7 +258,7 @@ export function usePage() {
scheduleRecoveryCodeHide()
recoveryConfigured.value = true
await globalStatus.refresh()
notify('恢复码已生成,请仅保存这一次显示的内容', 'success')
notify('恢复码已生成,请妥善保存;验证本人密码后可再次查看有效恢复码', 'success')
} catch (error) {
if (isRecentAuthenticationCancelled(error) || !isRecoveryViewCurrent(version)) return
if (error !== 'cancel' && error !== 'close') notify(error?.message || '离线恢复码生成失败')

View File

@ -23,8 +23,8 @@
<div v-if="codes.length" class="recovery-code-result">
<div v-if="!revealed" class="result-title">
<strong>新安全码仅显示这一次</strong>
<span>请立即交给用户妥善保存,关闭弹窗后无法再次查看。</span>
<strong>新安全码已生成</strong>
<span>请交给用户妥善保存。60 秒后自动隐藏,验证当前管理员密码后可再次查看有效安全码。</span>
</div>
<div v-else class="result-title">
<strong>当前有效安全码</strong>