React Router JWT保护路由

时间:2019-09-26 03:02:58

标签: reactjs react-router

我在laravel顶部有一个react应用,其中有一个使用jwt auth的自定义登录屏幕。我在本地存储中获得了令牌集,但是如果未登录,我会尝试保护和重定向路由。问题是在渲染路由之前检查令牌。我尝试过的一切,最终都陷入了一个巨大的循环。请帮忙。这是我的app.jsx

require('./bootstrap');

import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux'
import Login from './components/auth/login';
import Header from './components/header/';
import store from './store';
import Dashboard from './pages/dashboard';
import jwtDecode from 'jwt-decode';
import { PropsRoute, PublicRoute, PrivateRoute } from 'react-router-with-props';


let getToken = () =>{

  var auth = false;
  var token = localStorage.getItem('toobiauth')

  if(token){
    var tokenExpiration = jwtDecode(token).exp;
    var dateNow = new Date();

    if(tokenExpiration < dateNow.getTime()/1000){
        auth = false
    }else{
        auth = true
    }
  }else{
    auth = false
  }
  return auth;

}


ReactDOM.render((
  <Provider store={store}>
       <Router>
         <Header>
           <Switch> 
             <Route exact path='/' component={Login} />
             <Route exact path='/login' component={Login} />
             <PrivateRoute exact path="/dashboard" authed={getToken()} redirectTo="/login" component={Dashboard}/>
           </Switch>
           </Header>
       </Router>
    </Provider>
   ), document.getElementById('app'))

这是我的登录名

import React, { useState, useEffect } from 'react';
import { useSelector, useDispatch, connect } from "react-redux";
import Submit from '../ui/buttons/submit';
import Textfield from '../ui/inputs/textfield';
import {loginUser} from '../../actions/authactions';
import jwtDecode from 'jwt-decode';


function login(props) {

    const auth = useSelector(state => state.auth)
    const [username, setUsername] = useState();
    const [password, setPassword] = useState();

    const submitLogin = () =>{
        props.dispatch(loginUser(username, password))
    }

    useEffect(() =>{
        var token = localStorage.getItem('toobiauth')

        if(token){
            var tokenExpiration = jwtDecode(token).exp;
            var dateNow = new Date();

            if(tokenExpiration < dateNow.getTime()/1000){
                console.log('expired');
            }else{
                props.history.push('/dashboard')
                console.log('login screen')
            }
        }

    },[auth]);


    return <div className="page_wrapper">
        <Textfield type="text" change={setUsername}/>
        <Textfield type="password" change={setPassword}/>
        <Submit action={submitLogin} width={'100%'}/>
    </div>;
}

const mapStateToProps = (state) =>{
    return {
      app: state.app,
    }
}

export default connect(mapStateToProps)(login);

1 个答案:

答案 0 :(得分:2)

您可以定义自己的PrivateRoute.jsx,在该组件中,您可以检查用户是否已通过身份验证,然后允许用户路由受保护的路由,否则将用户重定向到登录路由

PrivateRoute.jsx

import React, { useEffect, useState} from 'react';
import { Route, Redirect } from 'react-router-dom'
import { useSelector } from "react-redux";

const PrivateRoute = ({ component: Component, ...rest }) => {
  const auth = useSelector(state => state.auth)
  const [isAuthenticated, setIsAuthenticated] = useState(null)  
  useEffect(() => {
    let token = localStorage.getItem('toobiauth')
        if(token){
            let tokenExpiration = jwtDecode(token).exp;
            let dateNow = new Date();

            if(tokenExpiration < dateNow.getTime()/1000){
                setIsAuthenticated(false)
            }else{
                setIsAuthenticated(true)
            }
        } else {
           setIsAuthenticated(false)
        }
    // eslint-disable-next-line
  }, [auth])

  if(isAuthenticated === null){
    return <></>
  }

  return (
    <Route {...rest} render={props =>
      !isAuthenticated ? (
        <Redirect to='/login'/>
      ) : (
        <Component {...props} />
      )
    }
    />
  );
};

export default PrivateRoute;

App.js

import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux'
import Login from './components/auth/login';
import Header from './components/header/';
import store from './store';
import Dashboard from './pages/dashboard';
// import new PrivateRoute component defined in codeblock above
import PrivateRoute from './components/PrivateRoute'
import jwtDecode from 'jwt-decode';

ReactDOM.render((
  <Provider store={store}>
       <Router>
         <Header>
           <Switch> 
             <Route exact path='/' component={Login} />
             <Route exact path='/login' component={Login} />
             <PrivateRoute exact path='/dashboard' component={Dashboard} />
           </Switch>
           </Header>
       </Router>
    </Provider>
   ), document.getElementById('app'))