Inject service or class in guard in NestJS - apache-kafka

Needs to DI Kafka client in guard:
auth.guard.ts
export class AuthGuard implements CanActivate {
private _client: ClientKafka; <----- // TODO implement nestjs DI mechanism
public async canActivate(context: ExecutionContext): Promise<boolean> {
try {
const request = context.switchToHttp().getRequest();
const authorization: string = request.get('Authorization');
...code here just send data to jwt service...
return true;
} catch (err) {
return false;
}
}
}
I use new in canActivate for creating an instance of Kafka client in auth.guard.ts. But how to inject a class in guard with #Inject? I used to create #Global module, which provides and export Kafka client class, but it's not working...

Use This in the module for globally using the guard
providers: [{provide: APP_GUARD, useClass: AuthGuard}]
As for your question about injecting a class inside a guard, you need to inject it inside the constructor of the AuthGuard class
export class AuthGuard implements CanActivate {
constructor(private clientKafka : ClientKafka){}
}
if this doesn't work, try using
constructor(#Inject(private clientKafka : ClientKafka)){}
Hope this resolves your issue :)

Related

Flutter Unit Test for Create Constructor

My question is: How can I run the test aiming to test de loadSpecies() called inside constructor initialize?
Class
class TodoProvider with ChangeNotifier {
TodoProvider() {
loadSpecies();
}
loadSpecies() {
/* Here is the request to API */
}
}
Test
What I need to do here?
test('Initialization', () async {
when(EstablishmentProvider());
});
Inside when you will have to mock the api request which you will be doing in loadSpecies() method.
Lets you are getting http client object inside your constructor like this:
class TodoProvider with ChangeNotifier {
final Client client;
TodoProvider(this.client) {
loadSpecies();
}
loadSpecies() {
/* Here is the request to API */
}
}
To mock the api, you will have create mock class of your http client.
class MockClient extends Mock implements Client {}
and then initialise an object of the MockClient
final client = MockClient();
Then, mock the api using client variable
when(()=> client.get(any()).thenAnswer(() async => \* return whatever object */);
To test the output of your method loadSpecies(), you can use expect() method

Auth JWT in decorator in NESTJS

how can i decode jwt cookies in a decorator in nestjs? i can't use "private readonly jwtService: JwtService" in decorator, i use jwt-decode but it still work while jwt is out of date
You can create a custom decorator in that case.
//user.decorator.ts
import { createParamDecorator, ExecutionContext } from '#nestjs/common';
export const User = createParamDecorator((data: any, ctx: ExecutionContext) => {
const request = ctx.switchToHttp().getRequest();
return request.user;
});
Now we can use this User decorator in controllers
//user.controller.ts
import { User } from './user.decorator';
#Get()
async getUser(#User() user) {
//console.log(user);
}
You should have to use AuthGuard to decode the JwtToken
Please refer below document from NestJs
https://docs.nestjs.com/security/authentication#implementing-passport-jwt

NestJS - How to create wrapping service over jwt service (from jwt module)

Sorry for my bad english, I'm from Ukraine :)
Could you tell me how can I create my own service, that extends of Jwt service provided jwt module from npm package? I want to create my own JwtService for catch errors and isolate duplicate logic for token creation and verification. Please, help me how can I do it. Code samples attached.
import { BadRequestException, Injectable } from '#nestjs/common';
import { JwtService as NestJwtService, JwtVerifyOptions } from '#nestjs/jwt';
#Injectable()
export class OwnJwtService extends NestJwtService {
constructor() {
super({});
}
async verifyAsync<T>(token: string, options?: JwtVerifyOptions): Promise<T> {
try {
const res = await super.verifyAsync(token, options);
console.log('res', res);
return res;
} catch (error) {
// My own logic here ...
throw new BadRequestException({
error,
message: 'Error with verify provided token',
});
}
}
}
or maybe I need to inject nestjs jwt service to my own service ? example:
import { BadRequestException, Injectable } from '#nestjs/common';
import { JwtService as NestJwtService, JwtVerifyOptions } from '#nestjs/jwt';
#Injectable()
export class OwnJwtService {
constructor(private readonly jwtService: NestJwtService) {}
async verifyAsync<T>(token: string, options?: JwtVerifyOptions): Promise<T> {
try {
const res = await this.jwtService.verifyAsync(token, options);
console.log('res', res);
return res;
} catch (error) {
throw new BadRequestException({
error,
message: 'Error with verify provided token',
});
}
}
}
and
import { JwtModule as NestJwtModule } from '#nestjs/jwt';
import { ConfigModule, ConfigService } from '#nestjs/config';
import { Module } from '#nestjs/common';
import { OwnJwtService } from 'src/modules/jwt/jwt.service';
#Module({
imports: [
NestJwtModule.registerAsync({
imports: [ConfigModule],
useFactory: async (configService: ConfigService) => ({
signOptions: {
expiresIn: process.env.JWT_EXPIRES_IN,
},
secret: process.env.JWT_SECRET,
secretOrPrivateKey: process.env.JWT_SECRET,
}),
inject: [ConfigService],
}),
],
providers: [OwnJwtService],
exports: [OwnJwtService],
})
export class JwtModule {}
but it doesn't work for me, and I have similar errors:
Error: Nest can't resolve dependencies of the OwnJwtService (?). Please make sure that the argument JwtService at index [0] is available in the AuthModule context.
First, notice that the JwtModule basically creates a module based on jsonwebtoken and your custom errors aren't meant to be dealt inside it.
Second, when you use registerAsync you are meant to get your ENV variables with the ConfigService as in configService.get('JWT_SECRET').
Third, your question is inefficient. The JwtModule already does everything you need. You just need to implement it. Again, just think of it as the jsonwebtoken package adapted for Nest. That's it.
On the signup, login and refreshtoken (if existing) routes you sign when you create a new token.
And in your requests middleware you verify.
One kind of a big issue with Nest is its documentation. It doesn't have everything you need. There might be more than one way to verify a route, but the most straightforward is just using Express middleware, as in a typical Express app.
To do this, you need to implement it in the AppModule like this:
#Module(...)
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer): MiddlewareConsumer | void {
consumer.apply(cookieParser(), AuthMiddleware).forRoutes('/');
}
}
In this example, I'm also registering the module cookieParser() because I send the tokens in a cookie. Other cookie modules will do, too. Both the NestModule and the MiddlewareConsumer come from #nestjs/common.
AuthMiddleware is a middleware I made using this skeleton...
export class AuthMiddleware implements NestMiddleware {
constructor(
private readonly configService: ConfigService,
private readonly jwtService: JwtService
) {}
async use(req: Request, res: Response, next: NextFunction) {
const { yourJwtToken } = req.cookies;
const isValidToken = this.jwtService.verify(
yourJwtToken,
this.configService.get('JWT_SECRET'),
);
if (!isValidToken) throw new UnauthorizedException();
// etc...
next();
}
}
Finally, what you might be asking to, is to apply the AuthGuard.
If you use the Passport ones, you need just to follow the documentation to apply them. They already throw errors if you. If you want to change it, just rewrite its methods.
You can also do it manually. Just use the console to generate a guard, and in there you can check authentication context.switchToHttp().getRequest() and return a boolean after checking the credentials and use the constructor to check the permissions if you want.
You might also skip the middleware config from above and implement the logic inside the guard if you will.
Again, I don't really think changing the JwtModule is the best idea here.

Using Custom Pipes in services in angular2

I want to call the my custom pipe inside Injectable service. I checked many threads in stackoverflow. But they talk about using custom pipes inside a component. Can u please help me here, any helpful link will be fine. Below is my custom pipe file:
import { Pipe, PipeTransform } from '#angular/core';
#Pipe({ name: 'unit' })
export class UnitPipe implements PipeTransform {
transform(val,unit, args) {
if(unit=='Metric') {
return val * 2;
}
else {
return val * 4;
}
}
}
And Iam trying to access this pipe in my service:
import { Injectable } from '#angular/core';
import { Http, Response, Headers, RequestOptions } from '#angular/http';
import { UnitPipe } from '../pipes/UnitPipe';
#Injectable()
export class SomeService {
constructor(http: Http, unitPipe: UnitPipe) {
this.http = http;
this.unitPipe = unitPipe;
}
transformUnit() {
return this.unitPipe.transform('10', 'Metric');
}
}
I have specified this in app.module.js
declarations: [UnitPipe],
providers: [UnitPipe]
And in my component.js, I am calling this service method & just checking the output in console:
import { Component, OnInit, EventEmitter, Input } from '#angular/core';
import { SomeService } from '../../services/SomeService';
#Component({
})
export class SomeClass implements OnInit {
constructor(someService: SomeService) {
this.someService = someService;
}
ngOnInit(): void {
console.log(this.someService.transformUnit());
}
}
But Iam getting below error
One more thing is, my plan is to call transformUnit method inside my service file 'SomeService', may be onload, where the function definition is present. Any thought on this?
Thank you.
Your pipe transform function expects 3 parameters:
transform(val,unit, args) {
...
}
You're providing only 2 parameters to it:
transformUnit() {
return this.unitPipe.transform('10', 'Metric');
}
Best solutions I can suggest is using an Optional/Default parameter:
Optional parameter - Change args to args?
OR
Default parameter - Change args to args = null // or some other default value
This will allow you to call the pipe function with 2 params, so no need for code changing in your service.
You can see in this TypeScirpt-Functions link, section called Optional and Default Parameters for more details.
Created a simple StackBlitz DEMO with your code to this in action. Initially you will see the error in SomeService file. Just change the pipe args param accordingly. refresh the page. The error is gone in SomeService.

InversifyJS: Injecting the class which extends non-injectable external module

Need help on implementation related to Inversify. I am creating a class which is extending EventEmitter from node. when I try to use inversify it says EventEmitter is not injectable. Following is the sample code
//Interface
export interface ISubscriber {
Connect(callback: Function);
on(event: string, listener: Function): this;
emit(event: string, ...args: any[]): boolean;
}
//Class
import {EventEmitter} from 'events';
#injectable()
class Subscriber extends EventEmitter implements ISubscriber {
logProvider: SCLogging.ILogger;
public constructor(
#inject(TYPES.ILogger) logProvider: SCLogging.ILogger,
#inject(TYPES.IConfig) config: IConfig
) {
super();
//Some Implementation
}
public Connect(callback) {
//Some Implementation
}
public on(event: string, listener: Function): this {
super.on(event, listener);
return this;
}
public emit(event: string, ...args: any[]): boolean {
return super.emit(event, ...args);
}
}
export { ISubscriber, Subscriber }
//Define Binding
kernel.bind<SCLogging.ILogger>(TYPES.ILogger).to(Logger);
kernel.bind<IConfig>(TYPES.IConfig).to(Config);
kernel.bind<ISubscriber>(TYPES.ISubscriber).to(Subscriber);
I get error
Error: Missing required #injectable annotation in: EventEmitter.
a very similar question has been already answered on the InversifyJS issues on Github:
You can invoke the decorator using the decorate function:
import { decorate, injectable } from "inversify";
decorate(injectable(), ClassName)
Check out https://github.com/inversify/InversifyJS/blob/master/wiki/basic_js_example.md for more info.
Please refer to the issue on Github for more information.
Setting skipBaseClassChecks: true in the container options disables this "feature" of inversify.
See this PR for more details https://github.com/inversify/InversifyJS/pull/841