带react钩子的react-router-dom不重定向到正确的路由

时间:2019-03-06 12:33:45

标签: reactjs typescript react-router-v4 react-hooks

我是新来的反应者,我确定有一个我不理解的解释,但是我找不到答案...

如果用户已登录,我想使用该应用程序,因此我遵循了一些指南并创建了HOC(PrivateRoute),但由于某些原因,我一直停留在该应用程序的登录页面中,

即使localStorage包含有效的JWT,并且我要求输入特定的路径(/ wallet / portfolio),它仍会将我重定向到登录页面, 有人可以帮我理解这个问题吗(我正在使用打字稿,但我确定它与问题无关)

我的主要组件(App.tsx)

//imports...

export const App = () => {
    const[jWTContext, setJWTContext] = useState(jWTContextInitialState);
    const[isLoggedIn, setIsLoggedIn] = useState(false);

    useEffect(() => {
        if (!isLoggedIn) {
            jWTContext.isValid().then(loggedIn => {
                    setIsLoggedIn(loggedIn);
                }
            ).catch(() => {setIsLoggedIn(false)});
        }
    });
    return (
        <JWTContext.Provider value={jWTContext}>
            <BrowserRouter>
                <Switch>
                    <PrivateRoute exact path="/wallet/portfolio"  component={AppPortfolio}  isSignedIn={isLoggedIn}/>
                    <Route exact path="/wallet/login" component={AppLogin} />
                    <Route exact path="/wallet/register" component={AppRegister} />
                    <Redirect to={isLoggedIn ? "/wallet/portfolio" : "/wallet/login"}/>
                </Switch>
            </BrowserRouter>
        </JWTContext.Provider>
    );
};

PrivateRoute.tsx(从网络指南中复制...)

import * as React from 'react';
import {Route, Redirect, RouteProps} from 'react-router-dom';

interface PrivateRouteProps extends RouteProps {
    component: any;
    isSignedIn: boolean;
}

const PrivateRoute = (props: PrivateRouteProps) => {
    const { component: Component, isSignedIn, ...rest } = props;

    return (
        <Route
            {...rest}
            render={(routeProps) =>
                isSignedIn ? (
                    <Component {...routeProps} />
                ) : (
                    <Redirect
                        to={{
                            pathname: '/wallet/login',
                            state: { from: routeProps.location }
                        }}
                    />
                )
            }
        />
    );
};

export default PrivateRoute;

JWTContext.tsx(我的上下文提供程序):

import React from 'react';
import {JWTBody, JWTHeader, JWTToken} from "../interfaces/JWTToken"

export interface JWTContext {
    jWTToken: JWTToken | null;
    setJWTToken(jWTToken: JWTToken | null): void;
    isValid(): Promise<boolean>;
    updateFromLocalStorage(): (JWTToken | null);
}

export const jWTContextInitialState : JWTContext = {
    jWTToken: initFromLocalStorage(),

    setJWTToken: (jWTToken) => {
        jWTContextInitialState.jWTToken = jWTToken;
    },

    isValid: async() => {
        if (jWTContextInitialState.jWTToken) {
            let response = await fetch("/auth/tokenvalid",{
                method: "GET",
                headers: {
                    "Content-Type": "application/json",
                    "Authorization": JSON.stringify(jWTContextInitialState.jWTToken)}});
            let res = await response.json();
            if (res.code === 200)
                return true;
        }
        return false;
    },

    updateFromLocalStorage: () => {
        return initFromLocalStorage()
    }
};

function initFromLocalStorage() {
    let localStorageToken = localStorage.getItem("velonaJWT");
    if (localStorageToken) {
        return parseJwt(localStorageToken);
    }
    return null;
}


function parseJwt (token: string): JWTToken {
    token = token.replace("Bearer ", "");
    let tokenArray = token.split('.');

    let header = tokenArray[0];
    header = header.replace('-', '+').replace('_', '/');
    let bufferHeader = Buffer.from(header, "base64");
    let dataHeader: JWTHeader =  JSON.parse(bufferHeader.toString());

    let body = tokenArray[1];
    body = body.replace('-', '+').replace('_', '/');
    let bufferBody = Buffer.from(body, "base64");
    let dataBody: JWTBody =  JSON.parse(bufferBody.toString());

    return ({
        header: dataHeader,
        body: dataBody,
        sig: tokenArray[2]
    });
    //return  JWTToken(JSON.parse(bufferHeader.toString()), JSON.parse(bufferBody.toString()), tokenArray[2])
}


export const JWTContext = React.createContext(jWTContextInitialState);

最后是(JWTToken.tsx->仅用于接口)


// represent velona WJT token
export interface JWTToken {
    header: JWTHeader,
    body: JWTBody,
    sig: string,
}

export interface JWTHeader {
    typ: string,
    alg: string
}

export interface JWTBody {
    sub: number,
    jti: string,
    authorities: Authorities[],
    iat: number,
    nbf: number,
    exp: number,
    environment: string
}

export enum Authorities {
    ROLE_USER,
    ROLE_TRUSTEE,
    ROLE_EMPLOYEE,
    ROLE_ADMIN
}

1 个答案:

答案 0 :(得分:0)

@Tholle帮助我了解了这个问题, 因为起初用户未通过身份验证(直到JWT被服务器验证->异步),所以我们需要在react dom Switch中添加以下内容:

latitude

当然,缺点是,如果用户登录,他将无法进入任何公共页面(例如注册),但我可以接受...

感谢@Tholle