Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to redirect to login page for restricted pages in next.js?

In the udemy tutorial The Complete React Developer Course the additional package history was used to get the router outside a component for redirecting when the user is not authenticated:

/* AppRouter.js */
import createHistory from "history/createBrowserHistory";

const AppRouter = () => (
    <Router history={history}>
      <div>
        <Switch>
            <PublicRoute path="/" component={LoginPage} exact={true} />
            <PrivateRoute
                path="/dashboard"
                component={ExpenseDashboardPage}
            />
            <PrivateRoute path="/create" component={AddExpensePage} />
            <PrivateRoute path="/edit/:id" component={EditExpensePage} />
            <Route component={NotFoundPage} />
        </Switch>
      </div>
    </Router>
);

export default AppRouter;



/* PrivateRouter.js */
import React from "react";
import { connect } from "react-redux";
import { Route, Redirect } from "react-router-dom";
import Header from "../components/Header";

export const PrivateRoute = ({
    isAuthenticated,
    component: Component,
    ...rest
}) => (
    <Route
        {...rest}
        component={(props) =>
            isAuthenticated ? (
                <div>
                    <Header />
                    <Component {...props} />
                </div>
            ) : (
                <Redirect to="/" />
            )
        }
    />
);

const mapStateToProps = (state) => ({
    isAuthenticated: !!state.auth.uid
});

export default connect(mapStateToProps)(PrivateRoute);

The code for app.js is as follows:

/* app.js */
import AppRouter, { history } from "./routers/AppRouter";

const store = configureStore();

const jsx = (
    <Provider store={store}>
        <AppRouter />
    </Provider>
);

firebase.auth().onAuthStateChanged((user) => {
    if (user) {
        store.dispatch(login(user.uid));
        store.dispatch(startSetExpenses()).then(() => {
            if (history.location.pathname === "/") {
                history.push("/dashboard");
            }
        });
    } else {
        store.dispatch(logout());
        history.push("/");
    }
});

ReactDOM.render(jsx, document.getElementById("app"));

My question now is, how can I achieve this in my next.js project? I have tried a kind of similar way in the _app.js file. Can I accomplish this behavior somehow with the getInitialProps routine? In the zeit/next example with-firebase-authentication I have seen a combination of getInitialProps and componentDidMount, but was not successful to implement it in this way.

import withRedux from 'next-redux-wrapper';
import App from 'next/app';
import React from 'react';
import { Provider } from 'react-redux';
import { firebase } from '../src/firebase/firebase';
import reduxStore from '../src/redux/store';

class MyApp extends App {
  static async getInitialProps({ Component, ctx }) {
    firebase.auth().onAuthStateChanged((user) => {
      if (user) {
        console.log('log in');
      } else {
        if (ctx.isServer && ctx.req.url !== '/login') {
          ctx.res.writeHead(302, { Location: '/login' });
          ctx.res.end();
        }
        console.log('log out');
      }
    });

    return {
      pageProps: Component.getInitialProps
        ? await Component.getInitialProps(ctx)
        : {}
    };
  }

  render() {
    const { Component, pageProps, store } = this.props;

    return (
      <Provider store={store}>
        <Component {...pageProps} />
      </Provider>
    );
  }
}

// firebase.auth().onAuthStateChanged((user) => {
//   if (user) {
//     console.log('log in');
//   } else {
//     // router instance not accessible!
//     Router.push("/login");
//     console.log('log out');
//   }
// });

export default withRedux(reduxStore, { debug: false })(MyApp);
like image 392
multi_kulti Avatar asked Oct 20 '19 19:10

multi_kulti


People also ask

How do you redirect user back to the router came from after authentication in Nextjs?

To redirect back to the protected route the user was trying to access, you can pass a query parameter with the current path (protected route path) when redirecting to the login page. In the login page, once the login is complete, you can access the query parameter from router. query.

How do I redirect a user to login?

You can use session variable to do this, you ust be set session on login. So on edit page starting you can write following code to check wheter user is logged in or not.. your condition is bad, a simple issset($_SESSION) is not enough. another session might be set somewhere else.

How do I create a protected route in next Javascript?

js import React from "react"; import { useRouter } from "next/router"; const AuthContext = React. createContext(); const { Provider } = AuthContext; const AuthProvider = ({ children }) => { const [authState, setAuthState] = React.


1 Answers

import Router from "next/router";

export function redirectUser(ctx, location) {
  if (ctx.req) {
    ctx.res.writeHead(302, { Location: location });
    ctx.res.end();
  } else {
    Router.push(location);
  }
}

class MyApp extends App {
  static async getInitialProps({ Component, ctx }) {
    const { token } = parseCookies(ctx);

    let pageProps = {};

    if (Component.getInitialProps) {
      pageProps = await Component.getInitialProps(ctx);
    }

    // Restrict unauthorized user
    if (!token) {
      const isProtectedRoute =
        ctx.pathname === "/account" || ctx.pathname === "/create";

      if (isProtectedRoute) {
        redirectUser(ctx, "/signin");
      }
    }
    else {
      try {
         // Restrict user based on role on certain page
        const user;
        const isRoot = user.role === "root";
        const isAdmin = user.role === "admin";
        const isNotPermitted =
          !(isRoot || isAdmin) && ctx.pathname === "/create";

        if (isNotPermitted) {
          redirectUser(ctx, "/");
        }

        pageProps.user = user;
      }
      catch (err) {
        console.error("Error getting current user", err);

        destroyCookie(ctx, "token");
        redirectUser(ctx, "/signin");
      }
    }

    return { ...pageProps };
  }
}
like image 113
nymhays Avatar answered Sep 22 '22 12:09

nymhays