kriasoft / universal-router

A simple middleware-style router for isomorphic JavaScript web apps
https://www.kriasoft.com/universal-router/
MIT License
1.7k stars 104 forks source link

Recipe Request: Complex Route Redirection #133

Open tim-soft opened 6 years ago

tim-soft commented 6 years ago

Let's say I have an app with many user roles and many routes. Every route must be protected from unauthorized users and every route must be protected based on a list of permitted user roles.

If I'm understanding the docs correctly, a route is always evaluated starting from the root '/' and cascades down until the desired route is found.

What would be a good strategy for protecting a really large amount of routes for a large amount of reasons? My current plan is to add a function into every route which checks the user. This method feels a little tedious with a more complex app. Is there a more pragmatic pattern with Universal Router?

frenzzy commented 6 years ago

You can use middleware route like so (jsfiddle playground):

import UniversalRouter from 'universal-router';
import createBrowserHistory from 'history/createBrowserHistory';

const router = new UniversalRouter([
  { path: '', action: () => ({ content: 'Home Page' }) },
  { path: '/login', action: () => ({ content: 'Login Page' }) },
  { // middleware route
    path: '', // or '/admin' if you need to protect only admin routes
    action(context) {
      if (!context.user) {
        return { redirect: '/login', from: context.pathname  };
      }
      if (context.user.role !== 'Admin') {
        return { content: 'Access denied!' };
      }
      return context.next(); // go to child routes
    },
    children: [
      { path: '/protected', action: () => ({ content: 'Protected Page' }) },
      // ... (a lot of routes)
    ],
  },
]);

const history = createBrowserHistory();
function render(location) {
  router.resolve({
    pathname: location.pathname,
    user: null, // { name: 'Jhon', role: 'Guest' },
  }).then(page => {
    if (page.redirect) {
      history.push(page.redirect, { from: page.from });
    } else {
      document.body.innerHTML = page.content;
    }
  });
}

history.listen(render);
render(history.location); // initial render

or any other technique from redirects recipe