feat(login-guard): unlock entire scope and report deleted keys
Admin login-lock reset now SCANs and clears all auth:login:* keys (any scope) and surfaces redis_deleted_keys / fallback_deleted_keys back to ops-web so the operator can tell whether the cache was actually hit. Also tracks paired keys via a per-identifier index plus an unlock marker so legacy/in-flight pair locks get cleared on the next acquire. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -19,15 +19,15 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
ActionAdminUserCreate = "admin_user.create"
|
||||
ActionAdminUserUpdateProfile = "admin_user.update_profile"
|
||||
ActionAdminUserChangePlan = "admin_user.change_plan"
|
||||
ActionAdminUserChangeRole = "admin_user.change_role"
|
||||
ActionAdminUserChangeExpiry = "admin_user.change_expiry"
|
||||
ActionAdminUserResetUsage = "admin_user.reset_usage"
|
||||
ActionAdminUserSetKOL = "admin_user.set_kol"
|
||||
ActionAdminUserDisable = "admin_user.disable"
|
||||
ActionAdminUserEnable = "admin_user.enable"
|
||||
ActionAdminUserCreate = "admin_user.create"
|
||||
ActionAdminUserUpdateProfile = "admin_user.update_profile"
|
||||
ActionAdminUserChangePlan = "admin_user.change_plan"
|
||||
ActionAdminUserChangeRole = "admin_user.change_role"
|
||||
ActionAdminUserChangeExpiry = "admin_user.change_expiry"
|
||||
ActionAdminUserResetUsage = "admin_user.reset_usage"
|
||||
ActionAdminUserSetKOL = "admin_user.set_kol"
|
||||
ActionAdminUserDisable = "admin_user.disable"
|
||||
ActionAdminUserEnable = "admin_user.enable"
|
||||
ActionAdminUserResetPassword = "admin_user.reset_password"
|
||||
ActionAdminUserResetLoginLock = "admin_user.reset_login_lock"
|
||||
)
|
||||
@@ -179,6 +179,15 @@ type ResetAdminUserPlanUsageResult struct {
|
||||
Reset ResetPlanUsageView `json:"reset"`
|
||||
}
|
||||
|
||||
type ResetLoginLockResult struct {
|
||||
ID int64 `json:"id"`
|
||||
RedisDeletedKeys int64 `json:"redis_deleted_keys"`
|
||||
FallbackDeletedKeys int `json:"fallback_deleted_keys"`
|
||||
RedisScanPatterns []string `json:"redis_scan_patterns"`
|
||||
RedisAddr string `json:"redis_addr,omitempty"`
|
||||
RedisDB int `json:"redis_db"`
|
||||
}
|
||||
|
||||
func toAdminUserView(u *repository.AdminUserRecord) AdminUserView {
|
||||
return AdminUserView{
|
||||
ID: u.ID,
|
||||
@@ -603,24 +612,31 @@ func (s *AdminUserService) ResetPassword(ctx context.Context, actor *Actor, id i
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *AdminUserService) ResetLoginLock(ctx context.Context, actor *Actor, id int64) error {
|
||||
func (s *AdminUserService) ResetLoginLock(ctx context.Context, actor *Actor, id int64) (*ResetLoginLockResult, error) {
|
||||
user, err := s.users.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
if errors.Is(err, repository.ErrAdminUserNotFound) {
|
||||
return response.ErrNotFound(40430, "user_not_found", "用户不存在")
|
||||
return nil, response.ErrNotFound(40430, "user_not_found", "用户不存在")
|
||||
}
|
||||
return response.ErrInternal(50034, "query_failed", "failed to get user")
|
||||
return nil, response.ErrInternal(50034, "query_failed", "failed to get user")
|
||||
}
|
||||
|
||||
result := &ResetLoginLockResult{ID: id}
|
||||
if s.loginGuard != nil {
|
||||
_ = s.loginGuard.Unlock(ctx, user.Phone)
|
||||
if user.Email != nil && *user.Email != "" {
|
||||
_ = s.loginGuard.Unlock(ctx, *user.Email)
|
||||
unlock, err := s.loginGuard.UnlockWithResult(ctx, user.Phone)
|
||||
if err != nil {
|
||||
return nil, response.ErrServiceUnavailable(50305, "login_guard_unavailable", "登录保护暂时不可用,请稍后重试")
|
||||
}
|
||||
result.RedisDeletedKeys = unlock.RedisDeletedKeys
|
||||
result.FallbackDeletedKeys = unlock.FallbackDeletedKeys
|
||||
result.RedisScanPatterns = unlock.RedisScanPatterns
|
||||
result.RedisAddr = unlock.RedisAddr
|
||||
result.RedisDB = unlock.RedisDB
|
||||
}
|
||||
if actor != nil {
|
||||
_ = s.audits.Append(ctx, actor.audit(ActionAdminUserResetLoginLock, "admin_user", id, nil))
|
||||
}
|
||||
return nil
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s *AdminUserService) mapWriteError(err error) error {
|
||||
|
||||
Reference in New Issue
Block a user