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);
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.
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.
js import React from "react"; import { useRouter } from "next/router"; const AuthContext = React. createContext(); const { Provider } = AuthContext; const AuthProvider = ({ children }) => { const [authState, setAuthState] = React.
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 };
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With