Nesting Wrappers

Both the redirection HOCs and authWrapper can be nested (composed) together to create additional constraints for auth. This is especially useful when you want to provide authorization checks, such as checking a user is logged in and also an administrator.

For example, we can create a button that will only display for logged in users named Bob:

const onlyBob = authWrapper({
  authenticatedSelector: state => state.user.firstName === 'Bob'
  wrapperDisplayName: 'UserIsOnlyBob',
})

const OnlyBobButton = onlyBob(MyButton)

When nesting redirection HOCs, it is important to pay attention to the order of the nesting, especially if you are using a different redirectPath or allowRedirectBack. Consider the following:

const userIsAuthenticated = connectedRouterRedirect({
  redirectPath: '/login',
  authenticatedSelector: state => state.user !== null,
  wrapperDisplayName: 'UserIsAuthenticated'
})

const userIsAdmin = connectedRouterRedirect({
  authenticatedSelector: state => state.user.isAdmin,
  redirectPath: '/app',
  wrapperDisplayName: 'UserIsAdmin',
  allowRedirectBack: false
})

// Now to secure the component: first check if the user is authenticated, and then check if the user is an admin
<Route path="admin" component={userIsAuthenticated(userIsAdmin(Admin))}/>

Because the userIsAuthenticated check happens first, if the users aren't logged in they will be sent to the /login first, skipping the admin check all together. Then once they've authenticated, they can be checked for if they are an admin. Otherwise, they would be sent to /app which might also be protected by a userIsAuthenticated and then get sent to /login from there (assuming another auth check). This would result in the user ending up at /app once they've authenticated, instead of at /admin if they are an admin but weren't logged in at the time.

Chaining using compose

Since Higher Order Components are functions, they can easily be chained together using compose to prevent accidentally applying them in the wrong order. compose can be imported from redux, or recompose:

import { compose } from 'redux'

// userIsAuthenticated and userIsAdmin from above
const userIsAdminChain = compose(userIsAuthenticated, userIsAdmin)

// Now to secure the component, you don't have to think which order to apply!
<Route path="admin" component={userIsAdminChain(Admin)}/>

results matching ""

    No results matching ""