Home > Software design >  How to authenticate with Routes in React.js
How to authenticate with Routes in React.js

Time:09-26

I use this method to show private pages to the user. The problem is that no page is displayed to me, but the logs that I put in PrivatePage work properly.

Components are correct because when I simply call the routes, the components are returned correctly but it has a problem with PrivatePage and does nothing.

function Auth() {
    return new Promise((resolve, reject) => {
        let appData = GetAppData();
        if (appData.UserToken.length == 0) {
            reject(-2);
        }

    let request = {
        Token: appData.UserToken,
        UserId: appData.UserId
    }

    axios.post("****UserValidUrl****", request).then(response => {
        switch (response.data.Type) {
            case 10:
                resolve(10);
                break;
            case -2:
                reject(-2);
                break;
            case -13:
                reject(-13);
        }
    }).catch(err => {
        reject(-13);
    })
})
}

const PrivatePage = ({children, ...rest}) => (
     return <Route
    {...rest}
    render={async ({location }) => {
        let type = 10;
        try {
            type = await Auth();
        } catch(e) {
            type = -13;
        }

        Log(type);

        switch (type) {
            case 10:
                return children;
                break
            case -2:
                return (
                    <Redirect
                        to={{
                            pathname: '/Auth/Login',
                            state: { from: location },
                        }}
                    />)

            case -13:
                return (
                    <Redirect
                        to={{
                            pathname: '/NotFound',
                            state: { from: location },
                        }}
                    />)
                break;
        }}
    }/>
)

export default function BasePage() {
    return (
        <div>
            <BrowserRouter>
                <Switch>
                    <Route exact path={"/Auth/Login"} component={Login}/>
                    <PrivatePage path={"/"}>
                        <Switch>
                            <Route exact path={"/"} component={Home}/>
                            <Route exact path={"/Dashboard/Home"} component={Home}/>
                            <Route exact path={"/Dashboard/Profile"} component={Profile}/>
                            <Route component={NotFound}/>
                        </Switch>
                    }/>
                </Switch>
            </BrowserRouter>
        </div>
    );
}

Error Text:

Error: Objects are not valid as a React child (found: [object Promise]). If you meant to render a collection of children, use an array instead.

CodePudding user response:

Maybe you can do something like this in your private route.

PrivatePage

const PrivatePage = ({ children, ...rest }) => (
  <Route
    {...rest}
    render={async ({ location }) => {
      let isAuthenticated = false;
      try {
        isAuthenticated = await Auth();
      } catch(e) {
        // If you want to log the error.
      }
    
      if (isAuthenticated) {
        return children;
      }
      return (
        <Redirect
          to={{
            pathname: '/login',
            state: { from: location },
          }}
        />
      );
    }}
  />
);

BasePage

export default function BasePage() {
    return (
        <div>
            <BrowserRouter>
                <Switch>
                    <Route exact path={"/Auth/Login"} component={Login}/>
                    <PrivatePage path={"/"}>
                        <Switch>
                            <Route exact path={"/"} component={Home}/>
                            <Route exact path={"/Dashboard/Home"} component={Home}/>
                            <Route exact path={"/Dashboard/Profile"} component={Profile}/>
                            <Route component={NotFound}/>
                        </Switch>
                    </PrivatePage>
                </Switch>
            </BrowserRouter>
        </div>
    );
}

EDIT

PrivatePage for specific numeric value in Auth.

const PrivatePage = ({children, ...rest}) => (
     return <Route
    {...rest}
    render={async ({location }) => {
        let authenticated = false;
        try {
            authenticated = await Auth();
        } catch(e) {
            // If you want to log the error.
        }

        if(authenticated === -2) {
          // redirect one
        } else if (authenticated === -13) {
          // redirect two
        } if (authenticated) {
            return children;
        }

        return (
            <Redirect
                to={{
                    pathname: "/Auth/Login",
                    state: { from: location },
                }}
            />
        );
    }}
/>
)

CodePudding user response:

Your navigation looks complex for authentication. you can treat your component as route and do routing as this.

Assuming that you have authenticated separately and you just check if it's good to go, instead of trying to authenticate every single time for route. If you prefer this authentication on route, still solution applies.

function AuthenticatedRoute({ children, ...props }) {
  const isAuthenticated = useContext(AuthenticationContext);

  return isAuthenticated ? (
    <Route {...props}>{children}</Route>
  ) : (
    <Redirect
      to={{
        pathname: '/login',
        state: { from: location },
      }}
    />
  );
}

and use it like:

<AuthenticatedRoute path="/Dashboard/Home" exact>
  <h1>Hey Doctor Strange! You made it</h1>
</AuthenticatedRoute>

I also have created a protected auth routing in this code sandbox for reference: https://codesandbox.io/s/cranky-poincare-l2c06?file=/src/App.js:262-488

  • Related