简体   繁体   中英

Reactjs Redirect to protected page after login not working after Authenticated

The router is not able to redirect to the protected page after login. I have built a login page that has /login and after login is supposed to redirect to /dashboard instead it stays there what I'm doing wrong here.

Here is the gist of my code or this my github link for complete code

Login page code

import React, { useState } from 'react'
import {
  CButton,
  CCard,
  CCardBody,
  CCardGroup,
  CCol,
  CContainer,
  CForm,
  CFormFeedback,
  CFormInput,
  CInputGroup,
  CInputGroupText,
  CRow,
} from '@coreui/react'
import CIcon from '@coreui/icons-react'
import { cilLockLocked, cilUser } from '@coreui/icons'
import axios from 'axios'
import qs from 'qs'
import Auth from '../../../Auth/Auth'

const Login = () => {
  const [validated, setValidated] = useState(false)
  const [error, setError] = useState(null)
  const [username, setUsername] = useState('')
  const [password, setPassword] = useState('')

  function handleChange(e) {
    const { name, value } = e.target
    setError(null)
    switch (name) {
      case 'username':
        setUsername(e.target.value)
        break
      case 'password':
        setPassword(e.target.value)
        break
    }
    e.preventDefault()
  }

  const handleSubmit = (event) => {
    const bodyFormData = new FormData()
    const form = event.currentTarget
    Auth.authenticate()
    setError(null)
    setValidated(true)
  }
  return (
    <div className="bg-light min-vh-100 d-flex flex-row align-items-center">
      <CContainer>
        <CRow className="justify-content-center">
          <CCol md={8}>
            <CCardGroup>
              <CCard className="p-4">
                <CCardBody>
                  <CForm
                    className="row g-3 needs-validation"
                    noValidate
                    validated={validated}
                    onSubmit={handleSubmit}
                  >
                    <h1>Login</h1>
                    <p className="text-medium-emphasis">Sign In to your account</p>
                    <CInputGroup className="mb-3">
                      <CInputGroupText>
                        <CIcon icon={cilUser} />
                      </CInputGroupText>
                      <CFormInput
                        id="username"
                        name="username"
                        placeholder="Username"
                        autoComplete="username"
                        onChange={handleChange}
                        required
                      />
                      <CFormFeedback invalid>Please input Username</CFormFeedback>
                    </CInputGroup>
                    <CInputGroup className="mb-4">
                      <CInputGroupText>
                        <CIcon icon={cilLockLocked} />
                      </CInputGroupText>
                      <CFormInput
                        id="password"
                        name="password"
                        type="password"
                        placeholder="Password"
                        autoComplete="current-password"
                        onChange={handleChange}
                        required
                      />
                      <CFormFeedback invalid>Please input password</CFormFeedback>
                    </CInputGroup>
                    <CRow>
                      <CCol xs={6}>
                        <CButton color="primary" type="submit" className="px-4">
                          Login
                        </CButton>
                        {error}
                      </CCol>
                    </CRow>
                    {/*<CRow>*/}
                    {/*  <CCol xs={6}>{error}</CCol>*/}
                    {/*</CRow>*/}
                  </CForm>
                </CCardBody>
              </CCard>
            </CCardGroup>
          </CCol>
        </CRow>
      </CContainer>
    </div>
  )
}

export default Login

The Auth.js file

const Auth = {
  isAuthenticated: false,
  authenticate() {
    this.isAuthenticated = true
  },
  signout() {
    this.isAuthenticated = false
  },
  getAuth() {
    return this.isAuthenticated
  },
}

export default Auth

App.js file

import React, { Component } from 'react'
import { HashRouter, Redirect, Route, Switch } from 'react-router-dom'
import './scss/style.scss'
import Dashboard from './views/dashboard/Dashboard'
import Auth from './Auth/Auth'

const loading = (
  <div className="pt-3 text-center">
    <div className="sk-spinner sk-spinner-pulse"></div>
  </div>
)

// Containers
const DefaultLayout = React.lazy(() => import('./layout/DefaultLayout'))

// Pages
const Login = React.lazy(() => import('./views/pages/login/Login'))

const PrivateRoute = ({ component: Component, ...rest }) => (
  <Route
    {...rest}
    render={(props) =>
      Auth.getAuth() ? (
        <Component {...props} />
      ) : (
        <Redirect
          to={{
            pathname: '/',
          }}
        />
      )
    }
  />
)

class App extends Component {
  render() {
    return (
      <HashRouter>
        <React.Suspense fallback={loading}>
          <Switch>
            <Route exact path="/login" name="Login Page" render={(props) => <Login {...props} />} />
            {/*<Route path="/" name="Home" render={(props) => <DefaultLayout {...props} />} />*/}
            <Route exact path="/" name="Login Page" render={(props) => <Login {...props} />} />
            <PrivateRoute
              path="/dashboard"
              name="Dashboard Page"
              render={(props) => <Dashboard {...props} />}
            />
          </Switch>
        </React.Suspense>
      </HashRouter>
    )
  }
}

export default App

I have this implemented in a slightly different way, and it works so I'm going to share it, maybe it helps:

This is similar to your PrivateRoute :

const ProtectedRoute = (props) => {
  const { state } = useOvermind();

  return (
    <Route {...props}>
      {state.user.isLoggedIn === true && props.children}
      {state.user.isLoggedIn !== true && <Redirect to="/login" />}
    </Route>
  );
};

Then on the App.js I have:

(...)
<Router>
  <Switch>
    <Route path="/login" component={LoginScreen} />
    <Route path="/">
      <ProtectedRoute exact={true} path="/">
        <DashboardScreen />
      </ProtectedRoute>
      {state.user.isAdmin && (
        <ProtectedRoute path="/users">
          <UsersScreen />
        </ProtectedRoute>
      )}
      <ProtectedRoute path="/suppliers">
        <SuppliersScreen />
      </ProtectedRoute>
    </Route>
  </Switch>
</Router>
(...)

And on the Login screen I have:

const LoginScreen = (props) => {
  const { state } = useOvermind();

  return (
    <>
      {state.user.isLoggedIn && <Redirect to="/" />}
      {!state.user.isLoggedIn && (
        (... rest of code here...)
      )}
    </>
  );
};

Like Chris just mentioned on the comments, you need to update your state in order for the code to work. In my case I'm using Overmind for state management, and I update user.isLoggedIn (which starts as false ) to true , after a successful Login api call.

Also on the App.js I'm just showing the code inside the render function, specifically related to the Router .

On App.js I also use another boolean ( state.user.isAdmin ) to only show a link to the users screen, if the user is an Administrator. Of course, inside of the Users screen I also have a verification, similar to the one on the Login screen, which verifies if state.user.isAdmin===true to allow rendering the screen, otherwise it redirects again to the main screen ( <Redirect to="/" /> ).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM