Closed touagueni closed 4 years ago
Did you call app.component('JWTAuthenticationComponent')
in src/application.ts
?
Please also make sure you use the latest version of loopback4-example-shopping
as we recently updated it to use newest LoopBack versions.
Hi Raymond,
Please, see below the content of the src/application.ts file:
import {authenticate, AuthenticationComponent} from '@loopback/authentication';
import {AuthorizationComponent} from '@loopback/authorization';
import {BootMixin} from '@loopback/boot';
import {
ApplicationConfig,
BindingKey,
createBindingFromClass
} from '@loopback/core';
import {
model,
property,
RepositoryMixin,
SchemaMigrationOptions
} from '@loopback/repository';
import {RestApplication} from '@loopback/rest';
import {
RestExplorerBindings,
RestExplorerComponent
} from '@loopback/rest-explorer';
import {ServiceMixin} from '@loopback/service-proxy';
import path from 'path';
import {JWTAuthenticationStrategy} from './authentication-strategies/jwt-strategy';
import {MongoDataSource} from './datasources/mongo.datasource';
import {
PasswordHasherBindings, RefreshTokenServiceBindings, TokenServiceBindings,
TokenServiceConstants,
UserServiceBindings
} from './keys';
import {User} from './models';
import {MyAuthenticationSequence} from './sequence';
import {BcryptHasher} from './services/hash.password.bcryptjs';
import {JWTService} from './services/jwt-service';
import {MyUserService} from './services/user.service';
import YAML = require('yaml');
export {ApplicationConfig};
/**
* Information from package.json
*/
export interface PackageInfo {
name: string;
version: string;
description: string;
}
export const PackageKey = BindingKey.create<PackageInfo>('application.package');
const pkg: PackageInfo = require('../package.json');
@model()
export class NewUser extends User {
@property({
type: 'string',
required: true,
})
password: string;
}
@authenticate.skip()
export class AvokapApplication extends BootMixin(
ServiceMixin(RepositoryMixin(RestApplication)),
) {
constructor(options?: ApplicationConfig) {
super(options);
this.setUpBindings();
// Bind authentication component related elements
this.component(AuthenticationComponent);
this.component(AuthorizationComponent);
/****** */
// authentication
this.add(createBindingFromClass(JWTAuthenticationStrategy));
// Set up the custom sequence
this.sequence(MyAuthenticationSequence);
// Set up default home page
this.static('/', path.join(__dirname, '../public'));
// Customize @loopback/rest-explorer configuration here
this.bind(RestExplorerBindings.CONFIG).to({
path: '/explorer',
});
this.component(RestExplorerComponent);
this.projectRoot = __dirname;
// Customize @loopback/boot Booter Conventions here
this.bootOptions = {
controllers: {
// Customize ControllerBooter Conventions here
dirs: ['controllers'],
extensions: ['.controller.js'],
nested: true,
},
};
}
setUpBindings(): void {
// Bind package.json to the application context
this.bind(PackageKey).to(pkg);
this.bind(TokenServiceBindings.TOKEN_SECRET).to(
TokenServiceConstants.TOKEN_SECRET_VALUE,
);
this.bind(TokenServiceBindings.TOKEN_EXPIRES_IN).to(
TokenServiceConstants.TOKEN_EXPIRES_IN_VALUE,
);
this.bind(TokenServiceBindings.TOKEN_SERVICE).toClass(JWTService);
// // Bind bcrypt hash services
this.bind(PasswordHasherBindings.ROUNDS).to(10);
this.bind(PasswordHasherBindings.PASSWORD_HASHER).toClass(BcryptHasher);
this.bind(UserServiceBindings.USER_SERVICE).toClass(MyUserService);
/*********************************************************** */
// Bind datasource
this.dataSource(MongoDataSource, UserServiceBindings.DATASOURCE_NAME);
//Bind datasource for refreshtoken table
this.dataSource(MongoDataSource, RefreshTokenServiceBindings.DATASOURCE_NAME);
/************************************************************ */
}
// Unfortunately, TypeScript does not allow overriding methods inherited
// from mapped types. https://github.com/microsoft/TypeScript/issues/38496
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
async start(): Promise<void> {
// Use `databaseSeeding` flag to control if products/users should be pre
// populated into the database. Its value is default to `true`.
if (this.options.databaseSeeding !== false) {
await this.migrateSchema();
}
return super.start();
}
async migrateSchema(options?: SchemaMigrationOptions): Promise<void> {
await super.migrateSchema(options);
// // Pre-populate products
// const productRepo = await this.getRepository(ProductRepository);
// await productRepo.deleteAll();
// const productsDir = path.join(__dirname, '../fixtures/products');
// const productFiles = fs.readdirSync(productsDir);
// for (const file of productFiles) {
// if (file.endsWith('.yml')) {
// const productFile = path.join(productsDir, file);
// const yamlString = fs.readFileSync(productFile, 'utf8');
// const product = YAML.parse(yamlString);
// await productRepo.create(product);
// }
// }
// // Pre-populate users
// const passwordHasher = await this.get(
// PasswordHasherBindings.PASSWORD_HASHER,
// );
// const userRepo = await this.getRepository(UserRepository);
// await userRepo.deleteAll();
// const usersDir = path.join(__dirname, '../fixtures/users');
// const userFiles = fs.readdirSync(usersDir);
// for (const file of userFiles) {
// if (file.endsWith('.yml')) {
// const userFile = path.join(usersDir, file);
// const yamlString = YAML.parse(fs.readFileSync(userFile, 'utf8'));
// const input = new NewUser(yamlString);
// const password = await passwordHasher.hashPassword(input.password);
// input.password = password;
// const user = await userRepo.create(_.omit(input, 'password'));
// await userRepo.userCredentials(user.id).create({password});
// }
// }
// // Delete existing shopping carts
// const cartRepo = await this.getRepository(ShoppingCartRepository);
// await cartRepo.deleteAll();
// // Delete existing orders
// const orderRepo = await this.getRepository(OrderRepository);
// await orderRepo.deleteAll();
}
}
I don't see something like https://github.com/strongloop/loopback4-example-shopping/blob/master/packages/shopping/src/application.ts#L77.
You'll have to add this.bind(RefreshTokenServiceBindings.REFRESH_TOKEN_SERVICE).toClass(...)
if you register all bindings without using the jwt component.
Raymond I only had to use the application.ts from the shpping application provided example. it works now, much appreciated. cheers T
Hi everyone!
I am using npm 6.14.8.
I have a working implementation of authentication from the loopback4-example-shopping. when trying to add the refresh token capability, I am facing the following:
Unhandled error in POST /refresh-login: 500 ResolutionError: The key 'services.authentication.jwt.refresh.tokenservice' is not bound to any value in context RequestContext-fFKtBWS_Tw2PmEVjTh7oKQ-3 (context: RequestContext-fFKtBWS_Tw2PmEVjTh7oKQ-3, binding: services.authentication.jwt.refresh.tokenservice, resolutionPath: controllers.AuthController --> @AuthController.constructor[6]) at RequestContext.getValueOrPromise (C:\avokap\backend\node_modules\@loopback\context\src\context.ts:810:13) at C:\avokap\backend\node_modules\@loopback\context\src\resolver.ts:159:20 at C:\avokap\backend\node_modules\@loopback\context\src\resolution-session.ts:157:13 at tryCatchFinally (C:\avokap\backend\node_modules\@loopback\context\src\value-promise.ts:222:14) at Object.tryWithFinally (C:\avokap\backend\node_modules\@loopback\context\src\value-promise.ts:197:10) at Function.runWithInjection (C:\avokap\backend\node_modules\@loopback\context\src\resolution-session.ts:156:12) at resolve (C:\avokap\backend\node_modules\@loopback\context\src\resolver.ts:143:38) at C:\avokap\backend\node_modules\@loopback\context\src\resolver.ts:246:12 at Object.resolveList (C:\avokap\backend\node_modules\@loopback\context\src\value-promise.ts:169:28) at resolveInjectedArguments (C:\avokap\backend\node_modules\@loopback\context\src\resolver.ts:224:10) at Object.instantiateClass (C:\avokap\backend\node_modules\@loopback\context\src\resolver.ts:62:25) at C:\avokap\backend\node_modules\@loopback\context\src\binding.ts:748:29 at Binding._getValue (C:\avokap\backend\node_modules\@loopback\context\src\binding.ts:604:14) at C:\avokap\backend\node_modules\@loopback\context\src\binding.ts:479:23 at C:\avokap\backend\node_modules\@loopback\context\src\resolution-session.ts:122:13 at tryCatchFinally (C:\avokap\backend\node_modules\@loopback\context\src\value-promise.ts:222:14)
Please, can anyone help?
Many Thanks in advance
Tofik