What you'll learn
- how to prevent unauthorized users from seeing user-interface sections in Webiny Admin Area
Learn more about the Webiny Security Framework in the Security Framework key topics section.
The code that we will cover in this tutorial can also be found in our GitHub examples repository.
Let's finish this tutorial by adding authorization checks in the actual user interface. What we want to achieve is having a piece of UI hide if the currently logged-in user doesn't have access to it (doesn't have necessary security permissions).
For starters, let's see how we can hide the Car Manufacturers menu items in the main menu, in cases where logged in user doesn't possess the necessary permissions.
By completing the previous Admin Area Package tutorial, in our Webiny Admin Area, we should have the following items in the main menu:
So, what we want to achieve here is the following:
- if the user is allowed to access the Car Manufacturers module, then make the menu item visible
- otherwise, if the user isn't allowed to access it, keep the menu item hidden
Note that when we say "has access", specifically in this case, we're going to check if the user can read Car Manufacturer entries.
The code for these menu items is located in the scaffolded
packages/car-manufacturers/admin-app/src/menus.tsx file. So, in there, we can add the following code:
If you're curious about the
CarManufacturersPermission type, check its definition in packages/car-manufacturers/admin-app/src/types.ts:24.
In order to actually compile the code changes we're about to make and see them in browser, we need to run the following Webiny CLI command:
To learn more, check out the Use the Watch Command guide.
As you may have noticed, we're using the exact same logic and code, that we previously used while trying to secure the
getCarManufacturer GraphQL resolver function. The only thing that's different is the way we fetch the currently logged in identity's permission. Here, we are using the
useSecurity React hook in order to first get the identity, and then, via the
getPermission method, the
In order to manually test this, we can just log in with a user that doesn't belong to the Car Manufacturers security group. In that case, if everything was done correctly, we should not be able to see the Car Manufacturers menu item:
And while this is much better than what we had earlier, note that the actual route, to which the Car Manufacturers menu item linked, is still accessible. In other words, if a user tried to enter the
/car-manufacturers URL path (route) into the browser manually, the view would still be shown. This is simply because the route itself isn't secured. So, let's see how we can do that.
To prevent unauthorized users from accessing the
/car-manufacturers URL path (route), let's jump to the
packages/car-manufacturers/admin-app/src/routes.tsx file, in which we're going to wrap our all of our child React components with the
So, with this newly added code in place, by entering the mentioned
/car-manufacturers URL path into the browser, we'd receive the following:
And that's how you secure your routes. Note that we've only checking if the logged in user possesses the
car-manufacturers permission. And although that's not a very authorization specific check, we can still consider is it as enough, since we can perform more specific checks within the rendered child React components.
Let's see how we can prevent rendering of React components, in case the logged in user is not authorized to see them.
For example, let's hide the New Car Manufacturer button, for users that aren't allowed to create new or update existing car manufacturers. This is determined via the
rwd property in our
car-manufacturers security permission object (letter
w must be present in the string).
To do that, let's jump to the
CarManufacturersDataList React component (
packages/car-manufacturers/admin-app/src/views/CarManufacturersDataList.tsx), in which we're going to wrap the
ButtonSecondary component with the
SecureView component. The following code shows how we can do that (for brevity, some of the code was excluded):
Once again, with this newly added code in place, we should no longer see the New Car Manufacturer button if the logged in user isn't allowed to create new or update existing car manufacturers (letter
w must be present in the
rwd property of our
car-manufacturers security permission object).
And that's how we can use the
SecureView React component to conditionally render a React component.
Note that, instead of the
SecureView React component, we could've also easily used the previously shown
useSecurity React hook. The component is used here mainly mainly for demonstration purposes and to raise awareness of its existence.
We've covered all of the possible ways you can perform authorization checks, while developing new Webiny Admin Area modules:
It's useful to know that that these utilities can be used outside of the Webiny Admin Area as well, like for example in a custom React application.
To learn more about how to use these in a custom React application, please check out the dedicated article (coming soon).
Furthermore, note that there are still places in the user interface, where we'd most probably want to perform authorization checks, using one of the shown utilities. For example, in the car manufacturers list, we certainly don't want to show the delete entry icon, if the user isn't allowed to perform the delete operation. Make sure to check the full code example to see how the rest of the authorization checks were implemented.
Finally, like in the previous GraphQL API section, in case you start seeing yourself copying some of the authorization related code, it's certainly recommended that you extract it into one or more separate utility React hooks or components. This way we're not repeating our selves (DRY) and our code will be more maintainable and less error-prone.
Should I use the
useSecurity React hook or the shown React components?#
Although all three approaches are valid, we recommend the
useSecurity React hook as your first choice. Utilize React components in scenarios where the hook is not the most appropriate solution or it simply cannot be used.