feat(M4): 生命周期 + 审计 — 到期锁定/回收 cron、审计查询/CSV 导出/每日归档、settings 动态策略
This commit is contained in:
+31
-12
@@ -25,9 +25,10 @@ var (
|
||||
|
||||
// UserService 外部用户生命周期服务:DB 记录 + system.Manager 系统账号操作。
|
||||
type UserService struct {
|
||||
db *gorm.DB
|
||||
sys system.Manager
|
||||
cfg *config.Config
|
||||
db *gorm.DB
|
||||
sys system.Manager
|
||||
cfg *config.Config
|
||||
settings *SettingService // 可选:默认 TTL 等策略覆盖(settings 表)
|
||||
}
|
||||
|
||||
// NewUserService 创建用户服务。
|
||||
@@ -35,6 +36,20 @@ func NewUserService(db *gorm.DB, sys system.Manager, cfg *config.Config) *UserSe
|
||||
return &UserService{db: db, sys: sys, cfg: cfg}
|
||||
}
|
||||
|
||||
// WithSettings 注入设置服务(settings 表覆盖策略默认值,PLAN F7)。nil 安全。
|
||||
func (s *UserService) WithSettings(settings *SettingService) *UserService {
|
||||
s.settings = settings
|
||||
return s
|
||||
}
|
||||
|
||||
// effectiveDefaultTTL 新账号默认有效期:settings 覆盖优先,否则用配置默认。
|
||||
func (s *UserService) effectiveDefaultTTL(ctx context.Context) time.Duration {
|
||||
if s.settings != nil {
|
||||
return s.settings.DefaultTTL(ctx)
|
||||
}
|
||||
return s.cfg.Policy.DefaultTTL
|
||||
}
|
||||
|
||||
// GetByUsername 按用户名查询外部用户(含或不含 ext_ 前缀均可)。
|
||||
func (s *UserService) GetByUsername(ctx context.Context, username string) (*model.User, error) {
|
||||
full := normalizeName(username, s.cfg.System.UserPrefix)
|
||||
@@ -118,7 +133,7 @@ func (s *UserService) Create(ctx context.Context, username, email, supervisor, p
|
||||
return nil, ErrUserExists
|
||||
}
|
||||
if ttl <= 0 {
|
||||
ttl = s.cfg.Policy.DefaultTTL
|
||||
ttl = s.effectiveDefaultTTL(ctx)
|
||||
}
|
||||
expireAt := time.Now().Add(ttl)
|
||||
u := &model.User{
|
||||
@@ -222,33 +237,37 @@ func (s *UserService) Enable(ctx context.Context, id uint) error {
|
||||
return s.db.WithContext(ctx).Model(&model.User{}).Where("id = ?", id).Update("status", model.UserStatusActive).Error
|
||||
}
|
||||
|
||||
// Extend 延长有效期:重设 expire_at(days<=0 用配置默认 TTL)。
|
||||
// Extend 延长有效期:重设 expire_at(days<=0 用默认 TTL,settings 覆盖优先)。
|
||||
// 已过期用户在回收期内可经此恢复(PLAN §2.2),恢复后同步密钥。
|
||||
func (s *UserService) Extend(ctx context.Context, id uint, days int) error {
|
||||
// 返回新的过期时间,供 handler 响应。
|
||||
func (s *UserService) Extend(ctx context.Context, id uint, days int) (time.Time, error) {
|
||||
u, err := s.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
return err
|
||||
return time.Time{}, err
|
||||
}
|
||||
ttl := time.Duration(days) * 24 * time.Hour
|
||||
if days <= 0 {
|
||||
ttl = s.cfg.Policy.DefaultTTL
|
||||
ttl = s.effectiveDefaultTTL(ctx)
|
||||
}
|
||||
newExpire := time.Now().Add(ttl)
|
||||
updates := map[string]any{"expire_at": newExpire}
|
||||
if u.Status == model.UserStatusExpired {
|
||||
if !s.systemAccountOK(ctx, u.Username) {
|
||||
return ErrSystemAccountMissing
|
||||
return time.Time{}, ErrSystemAccountMissing
|
||||
}
|
||||
keys, err := activeUserKeys(s.db, ctx, u.ID, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
return time.Time{}, err
|
||||
}
|
||||
if err := s.sys.SyncAuthorizedKeys(ctx, u.Username, keys); err != nil {
|
||||
return err
|
||||
return time.Time{}, err
|
||||
}
|
||||
updates["status"] = model.UserStatusActive
|
||||
}
|
||||
return s.db.WithContext(ctx).Model(&model.User{}).Where("id = ?", id).Updates(updates).Error
|
||||
if err := s.db.WithContext(ctx).Model(&model.User{}).Where("id = ?", id).Updates(updates).Error; err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
return newExpire, nil
|
||||
}
|
||||
|
||||
// Delete 删除并回收用户:删除系统账号(userdel -r)+ 家目录 + 密钥记录,
|
||||
|
||||
Reference in New Issue
Block a user