feat: 实现登录失败锁定功能
新增了登录失败次数统计和临时锁定机制,包括: 1. 定义登录锁定数据结构和数据库表结构 2. 实现租户级别的锁定状态持久化接口 3. 添加登录速率限制安全策略配置 4. 在登录流程中加入锁定前置检查和失败计数逻辑 5. 提供管理员手动解锁的内部API接口 6. 新增中文本地化的锁定提示文案
This commit is contained in:
@@ -4438,6 +4438,80 @@ func actionTokenCacheID(uid types.Uid, tokenID, action, target string) string {
|
||||
return uid.String() + ":" + strings.TrimSpace(tokenID) + ":" + strings.TrimSpace(action) + ":" + strings.TrimSpace(target)
|
||||
}
|
||||
|
||||
// LoginLockoutPersistenceInterface stores per-account login failure counters
|
||||
// and temporary lock state in each tenant business database.
|
||||
type LoginLockoutPersistenceInterface interface {
|
||||
Get(tenantID types.TenantID, accountHash string) (*types.LoginLockout, error)
|
||||
RecordFailure(tenantID types.TenantID, accountHash string, userID *int64, windowCutoff, now time.Time) (*types.LoginLockout, error)
|
||||
Lock(tenantID types.TenantID, accountHash string, lockedUntil, now time.Time) error
|
||||
Reset(tenantID types.TenantID, accountHash string) error
|
||||
Release(tenantID types.TenantID, accountHash string, now time.Time) error
|
||||
}
|
||||
|
||||
type loginLockoutMapper struct{}
|
||||
|
||||
// LoginLockouts is the singleton for login lockout state.
|
||||
var LoginLockouts LoginLockoutPersistenceInterface
|
||||
|
||||
func tenantLoginLockoutAdapter(tenantID types.TenantID) (adapter.TenantLoginLockoutAdapter, error) {
|
||||
if !tenantID.IsValid() {
|
||||
return nil, types.ErrMalformed
|
||||
}
|
||||
if router, ok := adp.(adapter.TenantRoutedAdapter); ok {
|
||||
business, _, err := router.TenantAdapterFor(tenantID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if lockAdp, ok := business.(adapter.TenantLoginLockoutAdapter); ok {
|
||||
return lockAdp, nil
|
||||
}
|
||||
}
|
||||
if lockAdp, ok := adp.(adapter.TenantLoginLockoutAdapter); ok {
|
||||
return lockAdp, nil
|
||||
}
|
||||
return nil, types.ErrUnsupported
|
||||
}
|
||||
|
||||
func (loginLockoutMapper) Get(tenantID types.TenantID, accountHash string) (*types.LoginLockout, error) {
|
||||
lockAdp, err := tenantLoginLockoutAdapter(tenantID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return lockAdp.TenantLoginLockoutGet(tenantID, accountHash)
|
||||
}
|
||||
|
||||
func (loginLockoutMapper) RecordFailure(tenantID types.TenantID, accountHash string, userID *int64, windowCutoff, now time.Time) (*types.LoginLockout, error) {
|
||||
lockAdp, err := tenantLoginLockoutAdapter(tenantID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return lockAdp.TenantLoginLockoutRecordFailure(tenantID, accountHash, userID, windowCutoff, now)
|
||||
}
|
||||
|
||||
func (loginLockoutMapper) Lock(tenantID types.TenantID, accountHash string, lockedUntil, now time.Time) error {
|
||||
lockAdp, err := tenantLoginLockoutAdapter(tenantID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return lockAdp.TenantLoginLockoutLock(tenantID, accountHash, lockedUntil, now)
|
||||
}
|
||||
|
||||
func (loginLockoutMapper) Reset(tenantID types.TenantID, accountHash string) error {
|
||||
lockAdp, err := tenantLoginLockoutAdapter(tenantID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return lockAdp.TenantLoginLockoutReset(tenantID, accountHash)
|
||||
}
|
||||
|
||||
func (loginLockoutMapper) Release(tenantID types.TenantID, accountHash string, now time.Time) error {
|
||||
lockAdp, err := tenantLoginLockoutAdapter(tenantID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return lockAdp.TenantLoginLockoutRelease(tenantID, accountHash, now)
|
||||
}
|
||||
|
||||
func tenantRegistrationInviteAdapter(tenantID types.TenantID) (adapter.TenantRegistrationInviteAdapter, error) {
|
||||
if !tenantID.IsValid() {
|
||||
return nil, types.ErrMalformed
|
||||
@@ -4606,6 +4680,7 @@ func init() {
|
||||
PCache = pcacheMapper{}
|
||||
Verifications = verificationMapper{}
|
||||
RegistrationInvites = registrationInviteMapper{}
|
||||
LoginLockouts = loginLockoutMapper{}
|
||||
Security = userSecurityMapper{}
|
||||
Relations = relationsMapper{}
|
||||
Favorites = favoritesMapper{}
|
||||
|
||||
Reference in New Issue
Block a user