首页 > 解决方案 > 登录后Reactjs重定向到受保护的页面在身份验证后不起作用

问题描述

登录后路由器无法重定向到受保护的页面。我已经建立了一个登录页面,/login并且在登录后应该重定向到/dashboard而不是停留在那里我在这里做错了什么。

这是我的代码的要点,或者这是我的完整代码的 github链接

登录页面代码

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

Auth.js 文件

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

export default Auth

应用程序.js 文件

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

标签: javascriptreactjsreact-hooks

解决方案


我以稍微不同的方式实现了这个,它可以工作,所以我要分享它,也许它有帮助:

这类似于您的PrivateRoute

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

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

然后在 App.js 我有:

(...)
<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>
(...)

在登录屏幕上我有:

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

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

就像克里斯刚刚在评论中提到的那样,您需要更新您的状态才能使代码正常工作。在我的例子中,我使用 Overmind 进行状态管理,并在成功的 Login api 调用之后更新user.isLoggedIn(以 开头false)为。true

同样在 App.js 上,我只是在渲染函数中显示代码,特别是与Router.

在 App.jsstate.user.isAdmin上,如果用户是管理员,我还使用另一个布尔值 ( ) 仅显示指向用户屏幕的链接。当然,在Users屏幕里面我也有一个验证,和Login屏幕上的类似,验证是否state.user.isAdmin===true允许渲染屏幕,否则再次重定向到主屏幕(<Redirect to="/" />)。


推荐阅读