【问题标题】:How to inject NestJS config into TypeORM entity?如何将 NestJS 配置注入 TypeORM 实体?
【发布时间】:2020-06-02 20:46:25
【问题描述】:

让我们简化 TypeORM 实体User

@Entity()
export class User extends BaseDatabaseEntity {
  @Column({
    length: 255,
  })
  public firstName!: string;

  @Column({ length: 60 })
  @Exclude()
  public password: string;

  @BeforeUpdate()
  @BeforeInsert()
  private hashPassword(): void {
    const tmpPassword = hashSync(
      this.password + 'config.auth.password.secret',
      genSaltSync(),
    );
    this.password = tmpPassword;
  }
}

}

我需要用 NestJS 的配置(来自 ConfigService 的命名空间)替换 config.auth.password.secret

export default registerAs('app', () => {
   return {
    password: {
      secret: process.env.AUTH_PASSWORD_SECRET,
    }
  };
});

,但实体不是 NestJS 结构的一部分,所以我不能像往常一样注入它。

如何在 TypeORM 实体中实现 NestJS 配置?

【问题讨论】:

    标签: typescript nestjs typeorm nestjs-config


    【解决方案1】:

    实体不是 NestJS 中可注入提供程序的一部分,因此本质上这是不可能的。但是,您可以将其作为服务代码的一部分,并在插入/更新之前在那里进行密码散列。

    【讨论】:

    • 是的,这正是我想做的,但我不确定如何让实体成为 NestJS 的一部分。你能举个例子吗?
    • 你不能。这就是我所说的。实体不是@Injectable(),也没有计划制作它们。相反,您应该将拥有逻辑移动到您的服务中。 This answer 更深入地解释了原因
    • 所以我应该从实体中完全删除方法或使它们像这样:hashPassword(generator: IUserPassGenerator)?
    • 如果您需要访问应该注入的服务,您需要在使用实体的服务中创建逻辑,或者将所需的服务注入使用实体的服务中实体并将所需的服务传递给实体的方法。就个人而言,我会选择前者而不是后者
    • @JayMcDoniel 但如果我需要 @Column({ type: DataType.ENUM(config.get('app.i18n.languages')) }) lang: string 。如果无法使用,此配置是什么。我以前在其他框架中没有看到。
    【解决方案2】:

    我也需要这个并想出了解决方法。如前所述,您不能将配置注入实体。

    我想出了在实体中使用我需要的配置值导出对象的解决方案:

    在应用模块中初始化配置:

      imports: [
        ConfigModule.forRoot({
          isGlobal: true,
          load: [defaultConfig]
        }),
    // .....other imports
      ]
    

    defaultConfig 是一个收集和检查配置值的函数。最重要的是,它将值设置为 STATIC_CONFIG 对象。

    export const STATIC_CONFIG = {
      WEB_APP_URL: '',
      BASE_URL: '',
    };
    
    export const defaultConfig = () => {
      const port = +(process.env[ENV_SERVER.PORT] || 3000);
      const production = process.env.NODE_ENV === 'production';
      const retVal = {
        PRODUCTION: production,
        PORT: port,
        BASE_URL: process.env.BASE_URL || 'http://localhost:3000',
        URL_PREFIX: process.env.URL_PREFIX || 'http://localhost:3000',
    //    ..... plenty of other values
      }
    
      if (retVal[ENV_S3.HOST] && !(retVal[ENV_S3.ACCESS] && retVal[ENV_S3.SECRET])) {
        // tslint:disable-next-line:no-console
        console.error('S3 configuration error: no access or secret set; exiting');
        process.exit(1);
      }
    
      STATIC_CONFIG.WEB_APP_URL = retVal.WEB_APP_URL;
      STATIC_CONFIG.BASE_URL = retVal.BASE_URL;
    
      return retVal;
    };
    
    

    最后在我的实体中,我使用STATIC_CONFIG 对象,例如:

      @Expose({ name: 'image', toPlainOnly: true, groups: [TG_MOBILE] })
      get mobileAppImage() {
        return this.id ? `${STATIC_CONFIG.BASE_URL}/static/image/${this.id}` : undefined;
      }
    

    【讨论】:

      【解决方案3】:
      @Entity()
      export class User extends BaseDatabaseEntity {
        @Column({
          length: 255,
        })
        public firstName!: string;
      
        @Column({
          length: 60,
          transformer: new PasswordTransformer(new ConfigService())
        })
        @Exclude()
        public password: string;
      }
      
      export class PasswordTransformer implements ValueTransformer {
        constructor(private config: ConfigService) {}
      
        from(value: string): string {
          return value;
        }
      
        to(value: string): string {
          return hashSync(
            this.password + this.config.get('AUTH_PASSWORD_SECRET'),
            genSaltSync(),
          );
        }
      }
      
      

      【讨论】:

        猜你喜欢
        • 2022-09-23
        • 2022-09-24
        • 2021-11-21
        • 2019-10-31
        • 2019-03-07
        • 2020-06-06
        • 2019-11-13
        • 2019-04-25
        • 2020-04-29
        相关资源
        最近更新 更多