Skip to content

Commit

Permalink
feat(example-multi-tenancy): use context configuration APIs for the a…
Browse files Browse the repository at this point in the history
…ction
  • Loading branch information
raymondfeng committed Apr 17, 2020
1 parent fdfde2d commit 0f93dc1
Show file tree
Hide file tree
Showing 8 changed files with 72 additions and 60 deletions.
44 changes: 22 additions & 22 deletions examples/multi-tenancy/README.md
Expand Up @@ -94,36 +94,36 @@ We group multiple registrations in `src/multi-tenancy/component.ts` using the
```ts
export class MultiTenancyComponent implements Component {
bindings = [
createBindingFromClass(MultiTenancyActionProvider),
...MultiTenancyComponent.createStrategyBindings(),
// Add the action
createBindingFromClass(MultiTenancyActionProvider, {
key: MultiTenancyBindings.ACTION,
}),
// Add strategies
createBindingFromClass(JWTStrategy).apply(
extensionFor(MULTI_TENANCY_STRATEGIES),
),
createBindingFromClass(HeaderStrategy).apply(
extensionFor(MULTI_TENANCY_STRATEGIES),
),
createBindingFromClass(QueryStrategy).apply(
extensionFor(MULTI_TENANCY_STRATEGIES),
),
createBindingFromClass(HostStrategy).apply(
extensionFor(MULTI_TENANCY_STRATEGIES),
),
];

static createStrategyBindings() {
return [
createBindingFromClass(JWTStrategy).apply(
extensionFor(MULTI_TENANCY_STRATEGIES),
),
createBindingFromClass(HeaderStrategy).apply(
extensionFor(MULTI_TENANCY_STRATEGIES),
),
createBindingFromClass(QueryStrategy).apply(
extensionFor(MULTI_TENANCY_STRATEGIES),
),
createBindingFromClass(HostStrategy).apply(
extensionFor(MULTI_TENANCY_STRATEGIES),
),
];
}
}
```

### Configure what strategies to be used

The `MultiTenancyBindings.STRATEGIES` binding configures what strategies are
checked in order.
The `MultiTenancyAction` can be configured with what strategies are checked in
order.

```ts
app.bind(MultiTenancyBindings.STRATEGIES).to(['jwt', 'header']);
app
.configure<MultiTenancyActionOptions>(MultiTenancyBindings.ACTION)
.to({strategyNames: ['jwt', 'header', 'query']});
```

### Register MultiTenancyAction
Expand Down
Expand Up @@ -5,7 +5,10 @@

import {Client, expect} from '@loopback/testlab';
import {ExampleMultiTenancyApplication} from '../..';
import {MultiTenancyBindings} from '../../multi-tenancy';
import {
MultiTenancyActionOptions,
MultiTenancyBindings,
} from '../../multi-tenancy';
import {setupApplication} from './test-helper';

describe('UserController with header-based multi-tenancy', () => {
Expand All @@ -14,7 +17,9 @@ describe('UserController with header-based multi-tenancy', () => {

before('setupApplication', async () => {
({app, client} = await setupApplication());
app.bind(MultiTenancyBindings.STRATEGIES).to(['jwt', 'header', 'query']);
app
.configure<MultiTenancyActionOptions>(MultiTenancyBindings.ACTION)
.to({strategyNames: ['jwt', 'header', 'query']});
});

before('create users', async () => {
Expand Down
Expand Up @@ -6,7 +6,10 @@
import {Client, expect, supertest} from '@loopback/testlab';
import {sign} from 'jsonwebtoken';
import {ExampleMultiTenancyApplication} from '../..';
import {MultiTenancyBindings} from '../../multi-tenancy';
import {
MultiTenancyActionOptions,
MultiTenancyBindings,
} from '../../multi-tenancy';
import {setupApplication} from './test-helper';

describe('UserController with jwt-based multi-tenancy', () => {
Expand All @@ -15,7 +18,9 @@ describe('UserController with jwt-based multi-tenancy', () => {

before('setupApplication', async () => {
({app, client} = await setupApplication());
app.bind(MultiTenancyBindings.STRATEGIES).to(['jwt', 'header', 'query']);
app
.configure<MultiTenancyActionOptions>(MultiTenancyBindings.ACTION)
.to({strategyNames: ['jwt', 'header', 'query']});
});

before('create users', async () => {
Expand Down
4 changes: 4 additions & 0 deletions examples/multi-tenancy/src/application.ts
Expand Up @@ -34,6 +34,10 @@ export class ExampleMultiTenancyApplication extends BootMixin(
});
this.component(RestExplorerComponent);

/*
* app.configure(MultiTenancyBindings.ACTION)
* .to({strategyName: ['jwt', 'header', 'query']});
*/
this.component(MultiTenancyComponent);

this.projectRoot = __dirname;
Expand Down
Expand Up @@ -3,12 +3,16 @@
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT

import {ContextTags, Getter, inject, Provider} from '@loopback/context';
import {config, ContextTags, Getter, Provider} from '@loopback/context';
import {extensionPoint, extensions} from '@loopback/core';
import {RequestContext} from '@loopback/rest';
import debugFactory from 'debug';
import {MultiTenancyBindings, MULTI_TENANCY_STRATEGIES} from '../keys';
import {MultiTenancyAction, MultiTenancyStrategy} from '../types';
import {
MultiTenancyAction,
MultiTenancyActionOptions,
MultiTenancyStrategy,
} from '../types';
const debug = debugFactory('loopback:multi-tenancy:action');
/**
* Provides the multi-tenancy action for a sequence
Expand All @@ -23,8 +27,8 @@ export class MultiTenancyActionProvider
constructor(
@extensions()
private readonly getMultiTenancyStrategies: Getter<MultiTenancyStrategy[]>,
@inject(MultiTenancyBindings.STRATEGIES, {optional: true})
private strategyNames = ['header'],
@config()
private options: MultiTenancyActionOptions = {strategyNames: ['header']},
) {}

/**
Expand Down Expand Up @@ -54,15 +58,13 @@ export class MultiTenancyActionProvider
}

private async identifyTenancy(requestCtx: RequestContext) {
debug('Tenancy strategy names configured', this.strategyNames);
debug('Tenancy action is configured with', this.options);
const strategyNames = this.options.strategyNames;
let strategies = await this.getMultiTenancyStrategies();
strategies = strategies
.filter(s => this.strategyNames.includes(s.name))
.filter(s => strategyNames.includes(s.name))
.sort((a, b) => {
return (
this.strategyNames.indexOf(a.name) -
this.strategyNames.indexOf(b.name)
);
return strategyNames.indexOf(a.name) - strategyNames.indexOf(b.name);
});
if (debug.enabled) {
debug(
Expand Down
36 changes: 16 additions & 20 deletions examples/multi-tenancy/src/multi-tenancy/component.ts
Expand Up @@ -5,7 +5,7 @@

import {Component, createBindingFromClass, extensionFor} from '@loopback/core';
import {MultiTenancyActionProvider} from './actions/multi-tenancy-action.provider';
import {MULTI_TENANCY_STRATEGIES} from './keys';
import {MultiTenancyBindings, MULTI_TENANCY_STRATEGIES} from './keys';
import {
HeaderStrategy,
HostStrategy,
Expand All @@ -15,24 +15,20 @@ import {

export class MultiTenancyComponent implements Component {
bindings = [
createBindingFromClass(MultiTenancyActionProvider),
...MultiTenancyComponent.createStrategyBindings(),
createBindingFromClass(MultiTenancyActionProvider, {
key: MultiTenancyBindings.ACTION,
}),
createBindingFromClass(JWTStrategy).apply(
extensionFor(MULTI_TENANCY_STRATEGIES),
),
createBindingFromClass(HeaderStrategy).apply(
extensionFor(MULTI_TENANCY_STRATEGIES),
),
createBindingFromClass(QueryStrategy).apply(
extensionFor(MULTI_TENANCY_STRATEGIES),
),
createBindingFromClass(HostStrategy).apply(
extensionFor(MULTI_TENANCY_STRATEGIES),
),
];

static createStrategyBindings() {
return [
createBindingFromClass(JWTStrategy).apply(
extensionFor(MULTI_TENANCY_STRATEGIES),
),
createBindingFromClass(HeaderStrategy).apply(
extensionFor(MULTI_TENANCY_STRATEGIES),
),
createBindingFromClass(QueryStrategy).apply(
extensionFor(MULTI_TENANCY_STRATEGIES),
),
createBindingFromClass(HostStrategy).apply(
extensionFor(MULTI_TENANCY_STRATEGIES),
),
];
}
}
4 changes: 0 additions & 4 deletions examples/multi-tenancy/src/multi-tenancy/keys.ts
Expand Up @@ -14,10 +14,6 @@ export namespace MultiTenancyBindings {
export const CURRENT_TENANT = BindingKey.create<Tenant>(
'multi-tenancy.currentTenant',
);

export const STRATEGIES = BindingKey.create<string[]>(
'multi-tenancy.strategies',
);
}

export const MULTI_TENANCY_STRATEGIES = 'multi-tenancy.strategies';
4 changes: 4 additions & 0 deletions examples/multi-tenancy/src/multi-tenancy/types.ts
Expand Up @@ -21,6 +21,10 @@ export interface MultiTenancyAction {
(requestContext: RequestContext): ValueOrPromise<Tenant | undefined>;
}

export interface MultiTenancyActionOptions {
strategyNames: string[];
}

/**
* Interface for a multi-tenancy strategy to implement
*/
Expand Down

0 comments on commit 0f93dc1

Please sign in to comment.