Lesson Description

The "RBAC Exercise" Lesson is part of the full, Permission Systems that Scale course featured in this preview video. Here's what you'd learn in this lesson:

Kyle instructs students to update all permission checks in the codebase to use the new "can" function, then walks through replacing the old role-based checks across the services layer and creating a helper function to handle the more complex department-based project read permissions.

Preview

Transcript from the "RBAC Exercise" Lesson

[00:00:00]
>> Kyle Cook: So from here what I actually want you to do is I want you to go ahead and start to use this particular system. You can actually download the exact code that I have by checking out the branch 3.5-RBAC-based access control checkpoint, and to be able to use this code, all you need to do is anywhere we have a permission, so you can just search for permission in our code. Just like that, and all you need to do is just replace this with whatever permission you want to check.

[00:00:24]
So in our case, we can come in here with our can function, we can import that. This is checking for edit project, so I'll pass it in our user, and we'll pass it in project colon edit, just like that. And it looks like I have a little bit of an error, let me make sure I'm spelling everything right, Project, I call it update instead edit, there we go. Now I've replaced that permission, so if they have the ability to actually update something, it'll show up properly inside of here.

[00:00:46]
So go ahead, spend 5 or so minutes just updating as many permissions as you can. Awesome. So hopefully you guys had a good chance to be able to try that out and actually see how this permission system works and hopefully you liked it a little bit better. So what we're going to do is we're going to go through and update the rest of the permissions in our application, so everywhere we have a permission comment, we're going to update those particular sections.

[00:01:09]
Since I'm already in this file, I might as well update this new document version right here. Again, we can take this can function, we're just going to be using it everywhere, and now instead of checking roles directly, we're just going to check, OK, can they create a new document? So we check for document, and I think we called it create, so we check for document create, and there we go, we now have these permissions set up on this particular page.

[00:01:29]
Now I'm just going to come in here with a quick little search for permission throughout our entire application. We actually already have that over here, and we're going to start with the services layer because that's where most of our permissions lie. So let's come into our service layer and update all of these different sections. So inside of our create document service, we can do essentially the same thing.

[00:01:46]
We get our can function, make sure we import that. We want to pass it in our user that we're checking our permissions on, and then we're just going to add in our permission we want to check, which is document create. Super straightforward, and you'll notice since we wrote everything in TypeScript, we had really great autocomplete. Now one thing that some people do is they will write these in the opposite direction, they prefer to write create colon document, because it reads a little bit better, can user create document?

[00:02:07]
I mean that's pretty much pure English that's being written. The reason I personally prefer to write these in the opposite direction is because usually when you implement a new feature, you're implementing one feature, I'm implementing documents or I'm implementing projects. So when you want to check what permissions does a project or document have, you can just type in document colon, and you can try to autocomplete, and you can see I now get a list of every permission that essentially is associated with this one resource.

[00:02:31]
That's the reason I like to do it this way. If you do it the other way, you type in create and you try to autocomplete, it'll show you every resource you can do creates for, which is usually not how people actually think when they're programming. So that's why I do it this way, again, up to you, however you like to do it. Now let's copy this down and use this for all of the rest of the sections in our application as well.

[00:02:50]
We're going to go down into update, and again, here's our permission for update, we're just going to change this to document update, and then we'll move down to delete and do the exact same thing here, and this should say document.delete. And I believe I actually have these reversed. We need to make sure that this has a question mark in front of it because we want to check, do they not have this permission?

[00:03:11]
Yes. I'm just looking at this code and I don't know if I'm misreading. Oh, there, I think you just said it. Yes, yeah, yeah, yes, the negation. I forgot to negate the these ones up here. Very easy thing to do. There we go, so now those are correct, we're just checking if they do not have permission, we throw an error, otherwise we continue on, it's essentially a guard clause for us. So that handles all of the permissions inside these three files.

[00:03:32]
These permissions right here, we don't actually have any permission check for yet because, as I said, everyone can read a document, but we might as well put the permission check into here because we now have that permission check. So we can say if the user, or sorry, if can, user, and then we can check documents and we want to check read, we now have that in place, and again, make sure I negate this, and we'll just throw that error, so I'll just copy that error from over here, throw a new authorization error, and we'll put that directly inside this section right there.

[00:04:03]
And again, we can even get rid of this unauthenticated stuff because it's automatically handled for us because we're checking to see if the users know inside of our can function. Again, to make our code a little bit easier to work with, and let me make sure, yeah, I prefix that with permission so we can come back and update this throughout the rest of the workshop. Let's do the exact same thing for getting project documents.

[00:04:20]
Again, we want to make sure that they can actually read them, so we'll come in here with a simple just check, can they read these things? If so, we're fine. And again, we don't need to do that unauthorized check or unauthenticated check because it's already handled for us. And then finally, same exact thing right here. Whoops, copied the wrong thing, there we go. Paste that down, make sure they can read documents before we return any document related information back to them.

[00:04:44]
So you can see already in our services this is quite easy and reads relatively pretty much like English, which is really nice. We'll now do the exact same thing inside of our projects service, let me just go to our project service. And let's update the exact same thing. This giant confusing little block we can almost entirely remove and replace with much simpler code. Let's get that can function, user, in our case this is a read because we're checking the project ID by getting it, so we can say project.

[00:05:10]
And we want to check read, but you'll notice we have a little bit of complexity. We have read all, we have read global, we have read own. We now have this essentially 3 different permissions that we need to check. So instead of checking all three of those in this one file, we're going to create a helper function to essentially wrap this for us. So what we can do inside this permission section, let's just create a brand new file, we'll call it projects.

[00:05:35]
And in here, we're going to create a simple helper function. We'll call this can read project, just like that, and all it's going to do is just do all these different checks for us, so we can come into this can read project, and we can do all these checks, so we know we're going to be taking in a user. Just like that, which we know we only need the role part of, so we're going to take our user type.

[00:05:57]
Get just the role from it. And of course it could be null, because this is essentially the exact same thing that we had inside of our other section as well. So now let's import that can function, and now we have those different checks that we have. So we have read all, that one's pretty self-explanatory. If the user can read all, we can just return true or whatever else you want, we can write this code however we want, you can make it one big if statement, multiple.

[00:06:17]
I'll break it into multiple because I find it a little bit easier to read. So first, if they can read all, then we're perfectly fine. Next, we need to do a quick check to see if the user. And we want to check to see if they can read a global department. So now we actually need the project itself being passed into here as well. So let's come in here, pass it in the project, and we only need the department, so we'll just pick that from our project itself, get the document or department just like that.

[00:06:48]
So now we have access to both the user as well as the project they're trying to access. So if they can read the global department, and the project dot department is equal to null, well then they have access to this, so we can just return true here as well. And then finally we need to do a check for if the department project is not global, so it has to be equal to their own department, so here, this one I called own department, so if the project is equal to the user department, which we want to put in our pick up here.

[00:07:23]
There we go. And of course it could be no, so we'll just put that all the way up here if user is equal to null, we'll just return false to get started because they don't have access to anything. There we go. So now we're returning true if it's a project that is within their own department and they have access to it, otherwise, we'll just come down here and return false. So this still isn't ideal, obviously, because now we have 3 different permissions handling the same thing, but at least it's consolidated into one single helper function to make it a little bit easier to work with.

[00:07:54]
And now we can use this can read project function essentially anywhere else inside of our code. So here we can just paste that down. Can read project. Make sure we import that, pass it in our user and our project. And if we cannot read that specific project, well then what we're going to do is just return null, so maybe they can't read the project, we're returning null just like that. So at least we've made that complicated check a little bit easier and consolidated into one place.

[00:08:18]
Still not ideal, but it's better than nothing. Now if we scroll up here, we don't actually need to worry about adding any additional checks because it's already handled in our database query for us, so that one's entirely done, and our whole service layer is essentially updated to use this brand new role-based access control system for all of our different permissions.

Learn Straight from the Experts Who Shape the Modern Web

  • 250+
    In-depth Courses
  • Industry Leading Experts
  • 24
    Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now