Please, help me to find how to optimize my code. I need to limit the data for logged user. To do that, I need to get UUID from JWT token from Request. But I don't like my approach because I have duplicates of code:
const jwt = request.headers.authorization.replace('Bearer ', '');
const json = this.jwtService.decode(jwt, { json: true }) as { uuid: string };
Any one know how I can optimize that?
Here is my controller's code.
import { Controller, Get, Put, Body, Param, UseGuards, Req } from '@nestjs/common';
import { SettingService } from '../services';
import { AuthGuard } from '@nestjs/passport';
import { ResultInterface } from '../interfaces';
import { Request } from 'express';
import { JwtService } from '@nestjs/jwt';
@Controller('settings')
export class SettingController {
/**
* @param service
* @param jwtService
*/
constructor(private readonly service: SettingService,
private readonly jwtService: JwtService) {
}
@UseGuards(AuthGuard('jwt'))
@Get()
async findAll(@Req() request: Request): Promise<ResultInterface> {
const jwt = request.headers.authorization.replace('Bearer ', '');
const json = this.jwtService.decode(jwt, { json: true }) as { uuid: string };
const data = await this.service.findAll(json.uuid);
return { rows: data };
}
@UseGuards(AuthGuard('jwt'))
@Get(':id')
async findOne(@Param('id') id: number, @Req() request: Request): Promise<ResultInterface> {
const jwt = request.headers.authorization.replace('Bearer ', '');
const json = this.jwtService.decode(jwt, { json: true }) as { uuid: string };
const data = await this.service.findOneById(id, json.uuid);
return { row: data };
}
@UseGuards(AuthGuard('jwt'))
@Put()
update(@Body() data: any, @Req() request: Request): Promise<any> {
const jwt = request.headers.authorization.replace('Bearer ', '');
const json = this.jwtService.decode(jwt, { json: true }) as { uuid: string };
return this.service.update(data, json.uuid);
}
}
The header typically consists of two parts: the type of the token, which is JWT, and the signing algorithm being used, such as HMAC SHA256 or RSA. For example: { "alg": "HS256", "typ": "JWT" } Then, this JSON is Base64Url encoded to form the first part of the JWT.
In order to make your code more readable and transparent, you can create a @AuthUser() decorator and reuse it across all of your controllers. When you are using AuthGuard('jwt') you already are decoding the token and if you are using jwt.decode function again you double decode the token.
I attached below and example of user decorator and order controller function that returns all my orders.
user.decorator.ts
import { createParamDecorator } from '@nestjs/common';
export const AuthUser = createParamDecorator((data, req) => {
return req.user;
});
order.controller.ts
@ApiOperation({ title: 'Get my orders' })
@Get('/me')
@UseGuards(AuthGuard('jwt'))
async findMyOrders(@AuthUser() user: any): Promise<Order[]> {
return this.orderService.findbyUserId(user._id);
}
You could create a JWTUtil that does that for you... Maybe something like this?
@Injectable()
export class JWTUtil {
constructor(private readonly jwtService: JWTService) {}
decode(auth: string): {uuid: string}{
const jwt = auth.replace('Bearer ', '');
return this.jwtService.decode(jwt, { json: true }) as { uuid: string };
}
}
And then use it like this:
@Controller('settings')
export class SettingController {
constructor(
private readonly jwtUtil: JWTUtil,
private readonly service: SettingService,
) {}
@Get()
@UseGuards(AuthGuard('jwt'))
async findAll(@Headers('Authorization') auth: string): Promise<ResultInterface> {
const json = await this.jwtUtil.decode(auth);
const data = await this.service.findAll(json.uuid);
//....
}
}
Also note that you can directly access the Authorization
header from the controller. Instead of passing through the Request
object.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With