使用 axios 和 JWT 响应受保护的路由

时间:2021-04-25 15:55:27

标签: node.js reactjs axios jwt react-router-dom

我正在尝试使用 Reatjs、nodejs 和 JWT 创建受保护的路由。问题是我的组件在我的 API 检查客户端令牌之前呈现。这是我正在尝试的代码:

import React, {useState, useEffect} from 'react';
import { Route, Redirect } from 'react-router-dom';
import AuthAPI from './../utils/AuthAPI';


const ProtectedRoute = ({children, ...rest}) => {

    const [isAuth, setIsAuth] = useState(false);

    const fetchData = async () => {
        await AuthAPI.isAuth((res)=>{ //API call
            setIsAuth(res); 
        });
    }

    useEffect(()=>{
        fetchData();
    },[]);

    return (
        <Route {...rest} 
            render={(props)=>{
                return(
                    isAuth ? children : <Redirect to='/' />
                );
            }} 
        />
    );

};

这是 API 调用:

static isAuth(callback){ //static method from the class 'AuthAPI' imported above
    const url = 'http://localhost:5000/api/Auth/checking';
    const options = {
                method: 'GET',
                url: url,
                headers: {
                    'Accept': 'application/json',
                    'Content-Type': 'application/json;charset=UTF-8',
                },
                data: {}
            }
    return axios(options)
    .then((response)=>{
        callback(true);
    }).catch((err)=>{
        callback(false);
    });
}

当我加载页面时,它直接重定向,因为状态 isAuth 默认设置为 false。 我已经使用这种代码模型来显示从 API 获取的内容列表,并且运行良好。我认为这不是最好的方法,但我发现的大多数示例都没有使用实际的 API,而只是在不使用承诺的情况下伪造身份验证。

编辑 1.2:

我已经尝试过这个代码,来自 Udendu Abasili :

import React, {useState, useEffect} from 'react';
import { Route, Redirect } from 'react-router-dom';
import AuthAPI from './../utils/AuthAPI';


const ProtectedRoute = ({children, ...rest}) => {

    const [isAuth, setIsAuth] = useState(false);
    const [isLoaded, setIsLoaded] = useState(false)

    useEffect(()=>{
        let mounted = true;

        AuthAPI.isAuth().then(()=>{
            if (mounted) {
                console.log("Worked"); //display Worked
                setIsLoaded(true); // This line 1
                setIsAuth(true); // This line 2
            }
        }).catch(()=>{
            if (mounted) {
                console.log("Failed"); 
                setIsLoaded(true);
                setIsAuth(false);
            }
        });

        return () => {
            mounted = false;
        }
    },[]);

    return (
        !isLoaded ?
            <h5>Loading</h5> : (
            <Route {...rest} 
                render={(props)=>{
                    console.log("--->",isAuth,",",isLoaded); // displays false, true
                    return(
                        isAuth ? children : <Redirect to='/' />
                    );
                }}
            /> 
        )
    );

};

export default ProtectedRoute;

我发现了一个奇怪的错误。如果我交换注释为“第 1 行”和“第 2 行”的行,它会起作用,否则不会。

1 个答案:

答案 0 :(得分:0)

react js 生命周期的工作方式是,返回组件在 useEffect 之前被调用(在第一次挂载时相当于 componentDidMount 的钩子)。因此,您需要创建一个加载器组件的形式(将 <Text>Loading</Text> 替换为实际的 CSS 加载器),等待您的 isAuth 函数完成。

const ProtectedRoute = ({children, ...rest}) => {

    const [isAuth, setIsAuth] = useState(false);
    const [loaded, setLoaded] = useState(false);

    const fetchData = async () => {
      //you need to add try catch here 
        await AuthAPI.isAuth((res)=>{ //API call
            setIsAuth(res); 
            setLoaded(true)
        });
    }

    useEffect(()=>{
        fetchData();
    },[]);

    return (
        loaded ?
            <Text>Loading</Text> : (
        <Route {...rest} 
            render={(props)=>{
                return(
                    isAuth ? children : <Redirect to='/' />
                );
            }} 
        )
        />
    );

};

正如您所说,这不是最好的方法。我不建议在受保护的路由组件中调用函数来检查身份验证。通常,我只是将 isAuthenticated 参数传递给 ProctectedRoute 组件,该组件在 Redux 的帮助下进行更新。你应该查一下