68. Role-based UI features

You'll probably recall in module four when we set up API authentication that we gave each user a role; either the admin role, or just a regular user role.

Then we protected certain endpoints so they couldn't be accessed by particular user types. For example, a regular user can't edit an item.

Well, Vue Auth also allows us to protect parts of our client app based on user role.

To do this, we first need to indicate to Vue Auth which role each user is. Hopefully you saw a few videos back that the "role" property in our API response got added to the Vue Auth user object.

The other thing we need to do is tell Vue Auth which property of the user to test for the role. So let's add a property rolesVar and assign to it "role".

client/auth.js

export default {
  ...
  rolesVar: "role"
}

Protecting routes

One thing we can use the role property for is to protect routes based on role.

To start with, we only want registered users to access the cart page. Currently, if a guest or admin user goes to this page, they can access it just fine.

So here in our router file, let's first add a meta property to route configuration.

Let's add a property auth and we can assign an array to this containing the user roles that are allowed to access the page. In this case, it's only the "user" role.

Vue Auth will now test that property against the logged in user's role when they try to access that route.

client/router.js

routes: [
  ...
  {
    path: "/cart",
    name: ROUTE_NAME_CART,
    component: () => import("@views/Cart"),
    meta: { auth: ["user"] }
  },
  ...

Test

Let's go to the browser now and make sure we're logged out by clearing the local storage and refreshing.

Now, if we click the cart icon now, you'll see we're redirected to the 403 forbidden page.

Guest only routes

For the login and register pages, we don't want a logged in user to be able to access these. If they want to use these pages they'll first need to log out.

So let's add a meta property on login route, and add an auth sub-property to that. We'll just assign false to auth, which indicates that any authenticated user can't access these pages.

Let's copy that and paste the same rule for the register route.

client/router.js

routes: [
  ...
  {
    path: "/login",
    name: ROUTE_NAME_LOGIN,
    component: () => import("@views/Auth"),
    meta: { auth: false }
  },
  {
    path: "/register",
    name: ROUTE_NAME_REGISTER,
    component: () => import("@views/Auth"),
    meta: { auth: false }
  },
  ...

Admin pages

Finally, we need to protect the admin pages to ensure only logged in admin accounts can access them.

Let's protect the sell route, which, you'll see shortly, is used to create new items. We'll again add the meta property, assign it an object, then add the auth property to that and assign an array with a single property "admin".

Let's copy that rule and also add it to the profile route and the edit route.

client/router.js

routes: [
  ...
  {
    path: "/sell",
    name: ROUTE_NAME_SELL,
    component: () => import("@views/Sell"),
    meta: { auth: ["admin"] }
  },
  {
    path: "/profile",
    name: ROUTE_NAME_PROFILE,
    component: () => import("@views/Profile"),
    meta: { auth: ["admin"] }
  },
  ...
  {
    path: "/items/:id/edit",
    name: ROUTE_NAME_EDIT,
    component: () => import("@views/Sell"),
    meta: { auth: ["admin"] }
  }
]

Role-based UI features

The role property has another handy use in our client app. We can use it to adapt the UI.

For example, on our item page, we have this addToCart button. Well, we've just made it to the admin user doesn't have access to the cart page, and therefore shouldn't be able to add an item to the cart.

Let's make this button only appear if the user is a guest or logged in as a regular user.

To do this, let's add a v-if to the button and we'll use the global $auth.check() API, method passing in the string "admin".

As you can probably guess, this will return true or false based on whether the authenticated user's role matches that string.

So let's also add a ! at the front of this expression since we want to show this button so long as the user is not the admin.

client/views/Item.vue

<v-btn
  v-if="!$auth.check('admin')"
  name="add-to-cart"
  large
  color="blue-grey darken-4 white--text"
  class="elevation-0 ma-0"
  @click="addToCart">Add To Cart</v-btn>

Cart icon

We also want to hide the cart icon in the nav bar which also serves as a link to the cart page.

So here in the StickyNav component we can hide this icon from the admin by adding the same conditional as we did to the add to cart button, v-if="!$auth.check('admin')".

client/components/StickyNav.vue

<v-btn
  v-if="!$auth.check('admin')"
  :to="{ name: ROUTE_NAME_CART }"
  icon

  ...
</v-btn>

Testing

To test these feature out, let's go to the item page. And since I'm currently logged in as a regular user, so you'll see the button, and the the cart icon as normal.

But if I go an login as admin, now the button and icon are hidden!

Discussion

0 comments