Howto get req.user in services in Nest JS - javascript

In a controller, I add the user object with a guard, inject some service and call that service to get some response. I have removed a lot of code for brevity.
#Controller()
#UseGuards(AuthGuard())
export class UserController() {
constructor(private readonly userService: UsersService) {
}
#Get(':id')
async findOne(#Param('id') id) {
return await this.userService.findOne(id);
}
}
Since I have the AuthGuard, I now know the user is logged in before entering :id route.
In the service I would do something like
#Injectable()
export class UsersService {
async findOne(id: number): Promise<User> {
return await this.usersRepository.findOne({where: {id: id}});
}
}
But of course we want to have some checks that the logged in user has access to the user it is querying. The question is now how do I get the current logged in user. I can send it as a parameter from the controller, but since a lot of the backend would need security checked on the current user, I'm not sure that is a good idea.
#Get(':id')
async findOne(#Param('id') id, #Req() req: any) {
return await this.userService.findOne(id, req.user);
}
Ideally, which doesn't work, I would be able to get it in the UserService:
async findOne(id: number, #Req req: any): Promise<User> {
if (id === req.user.id || req.user.roles.contains('ADMIN')) {
return await this.userRepository.findOne({where: {id: id}});
}
}
Or perhaps through injection in the UserService constructor
constructor(#Inject(REQUEST_OBJECT) private readonly req: any) {}
So, is there a better way to send the user object through the backend than always sending the request object in each function call?

Update March 2019
Since version v6, you can now inject the request object into a request-scoped provider:
import { REQUEST } from '#nestjs/core';
import { Request } from 'express';
#Injectable({ scope: Scope.REQUEST })
export class UsersService {
constructor(#Inject(REQUEST) private readonly request: Request) {}
}
Outdated answer
It's not possible to inject the user (or request) directly into the service. Nest.js does not yet support request-scoped providers. This might change with version 6. Until then, a service does not know anything about a request.
Logged in user
You can create a custom decorator #User. Using a decorator is preferable over injecting the request object because then a lot of nest's advantages get lost (like interceptors and exception filters).
export const User = createParamDecorator((data, req) => {
return req.user;
});
And then use it like this:
#UseGuards(AuthGuard())
#Get(':id')
async findOne(#Param('id') id, #User() user) {
return await this.userService.findOne(id, user);
}
Roles
You can create a RolesGuard that makes sure the logged in user has the required roles. For details, see this answer.

#Injectable({ scope: Scope.REQUEST }) worked for me, but I had a lot of problems when need inject on anothers services.
Exist a another alternative:
https://github.com/abonifacio/nestjs-request-context
For while its ok.

#Injectable({ scope: Scope.REQUEST }) worked for me, but I had a lot
of problems when need inject on anothers services.
Exist a another alternative:
https://github.com/abonifacio/nestjs-request-context
For while its ok.
Inject(REQUEST) doesn't work with any passport strategy due to its global state - issue. https://github.com/abonifacio/nestjs-request-context works fine.

Related

NestJS EventEmitter

I'm following the NestJS docs for creating an EventEmitter (Doc Link.
When I running my code I'm getting an error :
"[Nest] 129586 - 16/06/2021, 20:43:31 [ExceptionsHandler] this.eventEmitter.emit is not a function"
This is what my code looks like:
import { EventEmitter2 } from "#nestjs/event-emitter";
#EntityRepository(Auth)
export class AuthRepository extends Repository{
constructor(private eventEmitter: EventEmitter2) {
super();
}
private logger = new Logger(AuthRepository.name);
async createUser(authDao: SignUpDto): Promise {
const { password, username, role, email, dateOfBirth, fname, lname } = authDao;
let user = await this.findOne({ username });
if (user) {
throw new ForbiddenException("Username already taken");
}
user = this.create({ password, username, role });
await this.save(user).catch(e => this.logger.error(e));
this.eventEmitter.emit("user.created", {
fname, lname, dateOfBirth, email
});
};
}
I'm not sure what I'm missing here.
Nest will not do any DI on TypeORM Repository classes. This is because these classes have other dependencies necessary to them by TypeORM, such as entity managers, and connections. Injecting the EventEmitter is something that should be done in a regular NestJS Provider, and not a TypeO Repo class
One thing I would mention is that you want the line where you declare your class to look like this:
export class AuthRepository extends Repository<Auth> {
as shown here: https://docs.nestjs.com/techniques/database#custom-repository
The reason that the event emitter is not being injected properly is because Nest is already injecting other things into the constructor of a Repository subclass, so the signature doesn't match.
More importantly, this would be potentially considered a bad design, because the Repository should only be concerned with persistence operations on the entities. You might want to refactor this, and create a Service (Provider), and then inject both the eventEmitter and your repository into it. Then, in that service, you can call the createUser method on the repository instance, and follow it up with emitting the event.

I need to pass an x-authorization token in the http get request in angular

I'm trying to show an image on a drop-file in angular, and to do that I'm trying to return the file that is in my root directory C, with a get method in the [image]. But before it access the method that finds the file, the code passes through a SecurityInterceptor, and check if I have the x-authorization token, and I don't know how to pass it in this request.
Someone knows how to pass the token(x-authorization) in the link I used in [image] ?
<drop-file (fileChanged)="getImgFile($event)" (fileRemoved)="fileRemoved()" [image]="'http://localhost:8081/users/107/photo_profile?t=1598626871263.png'" alt=""></drop-file>
you can use this http request interceptor.
import { Injectable, Injector } from '#angular/core';
import { HttpInterceptor } from '#angular/common/http';
#Injectable({
providedIn: 'root'
})
export class TokenService {
intercept(request, next) {
const token: string = sessionStorage.getItem('TOKEN');
if (token) {
request = request.clone({
setHeaders: {
Authorization: token
}
});
}
return next.handle(request);
}
}
What I think is, you can use a separate async method to get the image from server. So when the async method calls the API, you can use your angular interceptor to attach the token.
When I say separate async method, it should usually come from a service.
And you can make a base64 data url from it.

How to create custom provider for third-party library in nestjs with access to request and response

I have a controller in nestjs as below
import * as dialogflow from 'dialogflow-fulfillment';
import { Request, Response } from 'express';
#Controller('dialogflow-fulfillment')
export class DialogflowFulfillmentController {
#Post()
async fulfill(#Req() request: Request, #Res() response: Response) {
const agent = new dialogflow.WebhookClient({ request, response });
}
}
Now for being able to unit test this controller I want to use custom provider and provide an instance of WebhookClient.
Something like below
{
provide: 'WebhookService',
useFactory: async () => new dialogflow.WebhookClient({??,??})
}
but problem is I need to get access to instance of request and response to create a new instance.
How can I do that? And how to inject it in each calls of fulfill?
In this case I'd suggest to write a facade (wrapper) around the library. The facade does not need to be unit tested since it simply propagates the parameters and does not contain logic (you could write a "facade test" instead which essentially tests the library code, I'd say an integration test is a better fit):
#Injectable()
export class WebHookClientFacade {
create(request, response) {
return new dialogflow.WebhookClient({ request, response });
}
}
And use the facade in your controller that is now testable:
constructor(private webHookClientBuilder: WebHookClientFacade) {}
#Post()
async fulfill(#Req() request: Request, #Res() response: Response) {
const agent = this.webHookClientBuilder.create(request, response);
}

Angular correct login flow and structure

I am trying to implement a frontend with angular, but I am not sure if my login and overall flow is correct.
I have a login component for the login page which sends the user information to an auth service for authentication, then I save the auth token in the localhost and send it with every get request for the user data, but also I need to check for expired jwt token so I logout the user and clear the localstorage from the information. But I am not sure where this logout should happen.
Also my home page displays 2 different views if the user is logged or not, so I have a boolean in the service that I check. This is my flow:
The login component: Here the error is bind to the html lets say if credentials are invalid
export class LoginComponent implements OnInit {
error : string;
constructor(private authService : AuthService) { }
ngOnInit() {
this.authService.login("Robocop1", "password").subscribe(
data =>{
localStorage.setItem('Authorization', data['token'])
this.auth.isLoggedIn = true
},
err => this.error = err['error']
);
}
}
Service component:
export class AuthService {
isLoggedIn : boolean = false
constructor(private httpClient : HttpClient) { }
login(username, password) {
return this.httpClient.post('http://localhost:8090/login', {
username,
password
})
}
}
This is my home component that checks first if the user is logged:
export class HomeComponent implements OnInit {
isLoggedIn : boolean
constructor(private auth : AuthService) { }
ngOnInit() {
this.isLoggedIn = this.auth.isLoggedIn
}
}
And displays different part of the html:
<div *ngIf="!isLoggedIn">
<p>
hey user
</p>
</div>
<div *ngIf="isLoggedIn">
<p>
not logged
</p>
</div>
So my question is is injetcing a dependencies in the home component ok just to check for single boolean and is there a better way to do it.
Also I can have another data component where I get user data from the database. In the post request I am sending the authentication token so I will have something like:
this.dataService.getItems().subscribe(
data =>{
this.userData = data
},
err => {
if(err['error' === 'Jwt token has expired'){
this.authService.logout()
}else{
this.error = err['error']
}
}
);
So is again injecting dependency just to call a logout method ok? should this logout method be in the authService or elsewhere?
So my question is is injetcing a dependencies in the home component ok
just to check for single boolean and is there a better way to do it.
If your application will be about a couple of simple pages and will not expand, your approach might be enough but for it the best practise is using Angular Route Guards
A route guard is a CanActivate implementation in which you implement your authentication/authorization logic to guard your routes (pages)
So is again injecting dependency just to call a logout method ok?
should this logout method be in the authService or elsewhere?
This should be done implementing an HttpInterceptor. So that you don't need to handle each http call for handling faulty responses or adding authorization tokens. Catching the error response inside your http interceptor and logging out is the way to go. That way you do not have to inject your corresponding service into each place this is required.
HttpInterceptor is also not a big deal. You can follow this step by step guide and implement your own

Calling a method of a react class in a Component

I am implementing Login Authentication in my reactjs aplication following the tutorial https://auth0.com/blog/adding-authentication-to-your-react-flux-app//
I have written a class call the AuthService and inside the AuthService I have a function call Login as shown below
import LoginActions from './LoginAction';
const URL_LOGIN = 'loginurl';
class AuthService {
login(username, password) {
// do something
}
}
Now, I am calling this Login method in my Login Component as shown below
//this function is to save data to the API
loginUser = (user) => {
// Here, we call an external AuthService.
Auth.login(user.username, user.password)
.catch(function(err) {
console.log("Error logging in", err);
console.log(err);
});
Everythin works well but when I submit data, I get the error
TypeError: WEBPACK_IMPORTED_MODULE_4__authentication_AuthService.a.login(...) is undefined
When I console log at the login method of the AuthService class, I see the returned data. I have looked around for a fast solution to this error but I have not gotten it. Any help on this will be appreciate.
I do not want to bring this action to the component as I am also going to use it in other areas of my application.
Also,I am a newbie to Reactjs as this is my first Authentication I am doing here.
Add the static keyword before the login method in the AuthService class.
I was waiting for djfdev to see an answer as in his comment:
You’ve defined login as an instance method, but are calling it like a static method. Either add the static keyword before the function name, or create an instance of Auth before calling login on it.
But it seems he's not providing an answer. What he meant that you can define a static method like:
static login(username, password) {
Or call login method in an instance like:
const auth = new Auth
auth.login(user.username, user.password)
Further, I hope you're exporting the class like:
export default AuthService
And importing it like:
import Auth from '...'
From my comment on the OP:
You’ve defined login as an instance method, but are calling it like a static method. Either add the static keyword before the function name, or create an instance of Auth before calling login on it.
So your two options are to, A) use the static keyword to define your method on the class itself:
import LoginActions from './LoginAction';
const URL_LOGIN = 'loginurl';
class AuthService {
static login(username, password) {
// do something
}
}
Or B) create an instance of Auth before calling the login method:
loginUser = (user) => {
// Here, we call an external AuthService.
new AuthService().login(user.username, user.password)
.catch(function(err) {
console.log("Error logging in", err);
console.log(err);
});
See the MDN docs for static
I solved this problem by adding static to the login method as advice above and removing the catch from it.

Categories

Resources