2

I'm building a web app that has role permissions based, admin, user and also products, product A, B, C, etc. I get these data from a backend api.

Currently, I'm using local storage and useContext hook to save and manipulate these data, but an user that knows it, can easily change this information and manipulate the front end, so I'm wondering now which approach I can use here.

My wish (if it's possible) is to get these information by backend after the login, and reuse the data freely in other components, just importing it, like an useContext hook.

I know that there is Redux, but since I'm using next.js, from what I saw, every rendering it will lose/refresh data, so it won't be usefull here.

I'm also using SWR, so, I tried to get these data from cache.get('key'), but the SWR call must be on the same component to get the data properly from the key cached. It's not working if a call the SWR on the e.g home page, and try to get it in other generic component.

What do you people suggest to go here?

Thanks!

RAFAEL DA SILVA
  • 99
  • 2
  • 11
  • If you are going to fetch data from API then you can create custom hooks to fetch these data that you can reuse in any component you want – Ashirbad Panigrahi Jun 22 '22 at 01:36
  • With this custom hook, every component that will be using it, it will perform a fetch to the backend? e.g if a call it from 3 different component, it will be 3 fetchs to the backend? – RAFAEL DA SILVA Jun 22 '22 at 01:40
  • Yes, but for some sensitive data like product price and all you need to fetch again data from backend – Ashirbad Panigrahi Jun 22 '22 at 01:49
  • Makes sense. The downside to do an api call in each component is that I have to wait until the fetch is completed. It can spoil the user experience and flow, but the pro is that the app will always have the data up to date, IMO. – RAFAEL DA SILVA Jun 22 '22 at 01:59

2 Answers2

0

I think you should authenticate your user, then store their access key and identifier in localStorage and global state.

When users access an authorization required page.

  1. You'll check for the access token if it doesn't exist on both global state and localStorage. Redirect (or alert) the authorization error.
  2. If there is an access token. Then send a request to the server with that access token. The server will be in charge of authorizing progress. And you will handle the logic on the front end based on the response from the server.

The thing is the authorization (checking permission for instance) should be done in the backend, not on the frontend

I don't know whether you can manipulate the implementation of the backend API or not. Hope it helps

Tu Le Thanh
  • 542
  • 1
  • 6
  • 18
  • The permissions for roles and products is been doing on the backend. The thing is. e.g. We have a page called Configurations on the front, and this page is only for admin and who has access to product A, how do you prevent to user access it? user can access it from 2 ways (I believe), by the URL or by the UI. With that said, I need to prevent the user acessing this page creating a logic that user can't see this option on the UI and not be able to access directly by URL. That's why I need to validate these rules on the frontend as well. Does it make sense to you? – RAFAEL DA SILVA Jun 22 '22 at 12:57
  • Then create a HOC (`withAuthorization` component for instance). In that component, you will check for currently logged-in user information stored in the global state and check for its role, and permission. If not fulfilled, return a 403 page. The user's information gets by sending a request to the backend API with an access key stored in localStorage. – Tu Le Thanh Jun 22 '22 at 14:10
  • With this approach, you don't have to worry about the user manipulating their role because they cannot modify their access token. And as long as the app is running, the information of the current user is live in the global store. So it just takes 1 request to get that information in beginning and you can wrap your component by `withAuthorization` HOC many times. – Tu Le Thanh Jun 22 '22 at 14:14
  • When you say 'global state', do you mean in which way, using contextAPI or other approach? – RAFAEL DA SILVA Jun 22 '22 at 14:19
  • you can use `useContext` hook or third-party libraries like redux or recoil. – Tu Le Thanh Jun 22 '22 at 14:20
0

Following the answers, I created a useContext to use in any component that I need.

Here is what I have in my context:

const [userRoles, setUserRoles] = useState<string[] | undefined>([])
    
const getUsersRoles = useCallback(async () => {
    const getUserRoles = await UsersService.getUsersRoles(userInfo.idUsuario)
    setUserRoles(getUserRoles.data)
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [])

Note: UsersService.getUsersRoles function is integration with the API

And how I use it in the component I need:

const { userRoles, getUsersRoles } = useAuth()

if (userRoles?.length === 0) {
  getUsersRoles()
  return <LoadingGIf tip="Carregando opções..." />
}

With this, I have the data I need here userRoles. And IF the user reload/refresh the page, getUsersRoles is requested and set the data to the userRoles

The downside to this, at least for me, is that I have to add this:

const { userRoles, getUsersRoles } = useAuth()
    
if (userRoles?.length === 0) {
  getUsersRoles()
  return <LoadingGIf tip="Carregando opções..." />
}

for every component I need to use the roles data, but I believe that's it. It's working fine and isn't request extra any endpoints of API.

If anyone has a contribuitions or improves to do in the code, fell free to do it.

RAFAEL DA SILVA
  • 99
  • 2
  • 11