// Package operation_password 提供全局操作密码的设置、查询与验证服务 // 操作密码以 bcrypt 哈希存储于 Redis,仅超级管理员可维护 package operation_password import ( "context" "github.com/redis/go-redis/v9" "golang.org/x/crypto/bcrypt" "github.com/break/junhong_cmp_fiber/pkg/constants" "github.com/break/junhong_cmp_fiber/pkg/errors" ) // Service 全局操作密码服务 type Service struct { redis *redis.Client } // New 创建操作密码服务实例 func New(rdb *redis.Client) *Service { return &Service{redis: rdb} } // Set 设置/修改全局操作密码 // 对明文密码做 bcrypt 哈希后永久存储到 Redis(无 TTL) func (s *Service) Set(ctx context.Context, password string) error { hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) if err != nil { return errors.Wrap(errors.CodeInternalError, err, "操作密码加密失败") } key := constants.RedisSystemOperationPasswordKey() if err := s.redis.Set(ctx, key, string(hash), 0).Err(); err != nil { return errors.Wrap(errors.CodeInternalError, err, "操作密码存储失败") } return nil } // IsSet 查询操作密码是否已设置 func (s *Service) IsSet(ctx context.Context) bool { key := constants.RedisSystemOperationPasswordKey() n, err := s.redis.Exists(ctx, key).Result() if err != nil { return false } return n > 0 } // Verify 验证操作密码是否正确 // key 不存在时返回"操作密码未设置"错误,密码错误时返回"操作密码错误" func (s *Service) Verify(ctx context.Context, inputPassword string) error { key := constants.RedisSystemOperationPasswordKey() hash, err := s.redis.Get(ctx, key).Result() if err == redis.Nil { return errors.New(errors.CodeInvalidParam, "操作密码未设置,请联系超级管理员") } if err != nil { return errors.Wrap(errors.CodeInternalError, err, "查询操作密码失败") } if err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(inputPassword)); err != nil { return errors.New(errors.CodeInvalidParam, "操作密码错误") } return nil }