sourcefuse / loopback4-starter

Loopback 4 starter application. Multi-tenant architecture supported. Authentication, Authorization, Soft deletes, environment vars, Audit logs, included.
MIT License
158 stars 59 forks source link

Help with tenant-aware operations #78

Closed dkmanolov closed 3 years ago

dkmanolov commented 3 years ago

Hi,

Thank you for providing this awesome boilerplate! Can you please help me with some samples on how to apply some tenant awareness. For example how to get all users that are part of my current user tenant, because /users returns all existing users in all tenants? I'm new to Loopback and I don't know if it is correct to bind the tenant in the repository and filter there or there is some different approach.

akshatdubeysf commented 3 years ago

Hi @dkmanolov,

Yes, you can bind the user/tenant at the repository level to restrict the access of users, by implementing a new function in the repository that only gives the filtered results based on this user/tenant; You can use the AuthenticationBindings.CURRENT_USER binding to get the current user -

@inject.getter(AuthenticationBindings.CURRENT_USER)
protected readonly getCurrentUser: Getter<IAuthUserWithPermissions | undefined>
dkmanolov commented 3 years ago

Thank you @akshatdubeysf !

sambathsrey commented 2 years ago

could you provide more specific example? Example I have a table "blog" in that that do i need an identifier column "tenant_id" to allow repository to filter?

akshatdubeysf commented 2 years ago

Hi @sambathsrey ,

You can use base repository like this one to add created by and modified by fields to your model, then simply use these fields to filter the data in the repository.

sambathsrey commented 2 years ago

In case the models are created by super_admin(dashboard). Which tenant that model belong to?

akshatdubeysf commented 2 years ago

Ok so each user can be related to multiple tenants, but each userTenantId is related to only one tenant, and the userTenantId is the one that you are supposed to save in the createdBy or modifiedBy fields. As even a superAdmin would get a token for only one tenant at a time, his userTenantId would be related to only the tenant he logged in for.

sambathsrey commented 2 years ago

Ok. column createdBy or modifiedBy defines the userTenant. So if we know the userTenant belong to which tenant then we can know the models belong to the same tenant as userTenant. I got it. But how to perform query like blogRepository.find({where: .......}). I have concern about it, could you provide me a snippet of code how to perform filter?

akshatdubeysf commented 2 years ago

I have shared the repo that does this for userTenantId, you just to replicate that for tenantId

akshatdubeysf commented 2 years ago

for example -

  async create(entity: DataObject<T>, options?: Options): Promise<T> {
    let currentUser = await this.getCurrentUser();
    currentUser = currentUser ?? options?.currentUser;
    if (!currentUser) {
      throw new HttpErrors.Forbidden(AuthErrorKeys.InvalidCredentials);
    }
    entity.tenantId = user.tenantId;
   return super.create(entity, options);
  }

and then -

repo.find({
  where: {
    tenantId: 'someId'
  }
});
sambathsrey commented 2 years ago

so in the model should we define tenantId as a foreign key or just a normal column?

akshatdubeysf commented 2 years ago

If the tenants model and your tenant aware model are in the same db, then you can keep it as a foreign key otherwise no.