Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

redirect route? authorized routes #10

Open
rstormsf opened this issue Sep 3, 2015 · 10 comments · May be fixed by #86
Open

redirect route? authorized routes #10

rstormsf opened this issue Sep 3, 2015 · 10 comments · May be fixed by #86

Comments

@rstormsf
Copy link

rstormsf commented Sep 3, 2015

How would you do this ? to make sure that the url is authorized

**Update:

Answer from @koistya on Gitter:

One way to do so is to have a route handler similar to this one const authorize = (state, next) => { if (!state.user) { state.redirect = '/login'; next(); } } and then in your routes file:
on('/admin/users', authorize, (state) => )
And add a handler in your render function which checks if state.redirect was set, and if so redirect user to the new location by using Location.pushState(null, state.redirect) on a client, and req.redirect(state.redirect) on server

--- Want to back this issue? **[Post a bounty on it!](https://www.bountysource.com/issues/26405822-redirect-route-authorized-routes?utm_campaign=plugin&utm_content=tracker%2F18115217&utm_medium=issues&utm_source=github)** We accept bounties via [Bountysource](https://www.bountysource.com/?utm_campaign=plugin&utm_content=tracker%2F18115217&utm_medium=issues&utm_source=github).
@mychaelgo
Copy link

@rstormsf can you give me full example?

@ChrisCinelli
Copy link

A redirect example would be useful.

@mfrye
Copy link

mfrye commented Nov 4, 2015

This is roughly what I have. I'm not satisfied but it works for now.

router.js

const authorize = (state, next) => {
  if (!state.isAuthenticated) {
    state.redirect = '/login'; next();
  }
}

// If trying to access login page when Authenticated
const redirectAuth = (state, next) => {
  if (state.isAuthenticated) {
    state.redirect = '/';
  }
}

const router = new Router(on => {

  on('*', async (state, next) => {
    const component = await next();
    return component && <App context={state.context}>{component}</App>;
  });

  // Authenticated pages
  on('/editor', async (state, next) => {

    authorize(state, next);

    return (
      <EditorPage />
    )
  });

    // Public pages
  on('/login', async (state, next) => {

    redirectAuth(state, next);

    return (
      <LoginPage />
    )
  });
})

app.js

function run() {
  let currentLocation = null;
  let currentState = null;

  // Make taps on links and buttons work fast on mobiles
  //FastClick.attach(document.body);
  ReactTapEvent();

  // Check cookies if already logged in
  AppActions.isLoggedIn();

  let isAuthenticated = AppStore.isAuthenticated();

  // Get user data if authenticated
  if (isAuthenticated) {
    let userId = AppStore.getAuth().userId;
    AppActions.getUser(userId);
  }

  // Re-render the app when window.location changes
  const unlisten = Location.listen(location => {
    isAuthenticated = AppStore.isAuthenticated();

    currentLocation = location;
    currentState = Object.assign({}, location.state, {
      path: location.pathname,
      query: location.query,
      state: location.state,
      isAuthenticated: isAuthenticated,
      context
    });

    render(currentState);
  });

...

@mychaelgo
Copy link

@mfrye what is ReactTapEvent() ?

@pokorson
Copy link

@koistya is there any possibility now to redirect to different route? I see that post is quite old and universal-router API has changed since then?

@frenzzy
Copy link
Member

frenzzy commented Jul 28, 2016

Admin route + redirect example:

client.js

import UniversalRouter from 'universal-router'
import { createHistory } from 'history'
import routes from './routes'

history = useQueries(createBrowserHistory())
history.listen(onLocationChange)
history.replace(history.getCurrentLocation()); // initial render

async function onLocationChange(location) {
  try {
    const routeActionResult = await UniversalRouter.resolve(routes, {
      path: location.pathname,
      store: { isAdmin: false },
      redirect(to) {
        const error = new Error(`Redirecting to "${to}"...`)
        error.status = 301
        error.path = to
        throw error
      }
    })

    syncOrAsyncClientSideRenderFn(routeActionResult)
  } catch (error) {
    if (error.status === 301) {
      history.replace(error.path || '')
      return
    }
    // log or display other errors here
  }
}

server.js

import express from 'express'
import UniversalRouter from 'universal-router'
import routes from './routes'

const server = express()
const port = process.env.PORT || 3000

app.get('*', async (req, res, next) => {
  try {
    const routeActionResult = await UniversalRouter.resolve(routes, {
      path: req.path,
      store: { isAdmin: false },
      redirect(to) {
        const error = new Error(`Redirecting to "${to}"...`)
        error.status = 301
        error.path = to
        throw error
      }
    })

    const html = syncOrAsyncServerSideRenderFn(routeActionResult)
    res.status(200).send(html)
  } catch(error) {
    if (error.status === 301) {
      req.redirect(status.path || '/')
      return
    }
    next(error)
  }
})

server.listen(port, () => {
  console.log(`Node.js app is running at http://localhost:${port}/`)
})

routes.js

export default [
  {
    path: '/',
    action() {
      return 'main page'
    }
  },
  {
    path: '/login',
    action() {
      return 'login page'
    }
  },
  {
    path: '/admin',
    action({ store, redirect }) {
      if (store.isAdmin) return 'admin page'
      return redirect('/login') // or return undefined to render 404 instead
    }
  }
]

@pokorson
Copy link

@frenzzy would be great to see such example in documentation :)

@langpavel
Copy link
Collaborator

@frenzzy It is needed do redirect through exception?

@frenzzy
Copy link
Member

frenzzy commented Aug 2, 2016

@langpavel nope, it is just the easiest way to stop executing all routing code. In other way you need to handle redirect in several places (for example in each root/parent route) or add implementation to the core of router. But I do not see anything wrong with the exception approach, because we still need to handle errors such as 404 or 500.

@jayprakash1
Copy link

@frenzzy It seems that there is already a try catch block for route action in resolve function which take precedence over the try catch block above. For now, I set a boolean for redirection when required and use that to redirect later.

@frenzzy frenzzy linked a pull request Mar 26, 2017 that will close this issue
20 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants