Skip to content
John Biundo edited this page Aug 25, 2019 · 2 revisions

Guards Chapter

With this chapter, if you want to follow along, check out the guards-start branch and continue to the following along section.

If you just want a final version of the project as of the end of the chapter, check out the guards-end branch, and proceed to the upon completion section.

Following along

Refer to the comments below, corresponding to chapter sections, to guide you through the code changes for nest cats as you proceed through the docs chapter.

Read through the Pipes chapter until you get to the Role-based authentication section, then return here.

Role-based authentication section

When you get to the Role-based authentication portion of the docs, go ahead and create the role.guard.ts file as described in this section. As before, we'll create a new folder in src/common for guards. After creating that folder, our project structure should look like:

nest-cats
└───src
    └───cats
    │   └───dto
    │   └───interfaces
    └───common
        └───filters
        └───guards
        └───middleware
        └───pipes

Once you've created the role.guard.ts file, go ahead and bind the guard almost as described in the Binding guards section of the docs. To make things a little smoother down the road, let's bind the guard to a single endpoint - POST /cats. Our POST /cats endpoint handler in src/cats/cats.controller.ts should now look like this:

  @Post()
  @UseGuards(RolesGuard)
  @UsePipes(new ValidationPipe({ transform: true }))
  async create(@Body() createCatDto: CreateCatDto) {
    this.catsService.create(createCatDto);
  }

As usual, you'll also need to import UseGuards and RolesGuard.

At this point, the guard we created will fire, but it always returns true from the canActivate() function, so we won't see any change in behavior. Try creating and querying cats to see this for yourself. Don't worry, we'll eventually tie these pieces together so you can see the guard in action.

Reflection

When you get to the Reflection section of the docs, read through until you understand the concept of creating a custom roles decorator.

Then, create roles.decorator.ts in src/common/decorators (by now, you know that you'll first create a decorators folder in src/common), and add the code as shown in the docs.

Putting it all together

Follow the instructions to update RolesGuard in src/common/guards/role.guard.ts in the Putting it all together section of the docs.

Finally, import the Roles custom decorator and apply the admin role to the POST /cats endpoint as shown at the end of the Reflection section. Your POST /cats route handler should now look like this:

  @Post()
  @Roles('admin')
  @UseGuards(RolesGuard)
  @UsePipes(new ValidationPipe({ transform: true }))
  async create(@Body() createCatDto: CreateCatDto) {
    this.catsService.create(createCatDto);
  }

Upon completion

We've now got a functioning guard on our POST /cats route. Test it as discussed below.

HTTPie requests for testing the authorization guard

Test our POST /cats route with a valid request:

http POST :3000/cats name=Fred age:=3 breed='Alley Cat'

You should receive an error like:

{
  "error": "Forbidden",
  "message": "Forbidden resource",
  "statusCode": 403
}

This shows us that our guard is functioning; we do not have the role admin, as required by the route.

At this point, we should pause to ask "So... just exactly how would we get the role admin on the route?". We've sort of approached this problem in reverse, so let's take a short step back. As mentioned in the docs, it's common practice in Express apps to attach a user object, including properties like role, to the request object. This opens up the topic of authentication -- in itself, a rather large topic -- which we cover in detail in a few places:

Neither of those tie in the roles we built here, so we'll add some commentary and code that ties these two pieces together when we get to the authentication chapter.

For now, you may want to comment out the @UseGuards(RolesGuard) decorator so it doesn't interfere with remaining chapters.

What's next

Next up is the Interceptors chapter.