在使用 react-router-dom 成功进行身份验证后,将用户重定向到他们请求的页面



我构建了一个公共路由组件,用于登录,以便在用户未通过身份验证时显示。每当未记录的用户单击受保护的路由时,他将被重定向到登录页面,在那里他可以输入凭据。我想要一种编程方式,以便如果他使用正确的凭据登录,则应将他重定向到他首先尝试访问的页面。例如,如果用户请求配置文件页面,则应在登录后将他重定向到该页面,如果用户请求设置页面,也会发生同样的情况。

截至目前,我只能将它们重定向到家庭路径/。有什么方法可以使用重定向,以便它知道用户请求的路径?

这是我当前用于公共路由组件的代码

export const PublicRoute = ({
isAuthenticated,
component: Component,
...rest
}: PublicRouteProps) => (
<Route
{...rest}
component={(props: any) => {
console.log(props.path);
return isAuthenticated.auth ? (
<Redirect to='/' />
) : (
<div>
<Component {...props} />
</div>
);
}}
/>
);
const mapStateToProps = (state: ReduxStoreState) => ({
isAuthenticated: state.isAuthenticated
});
export default connect(mapStateToProps)(PublicRoute);

你的问题不能那么容易回答。基本上,您需要记住用户想要访问的路径,以便在用户成功进行身份验证后重定向到该路径。

我在这里为您创建了一个示例。您可以在下面找到该示例中的说明和一些代码。

因此,如果用户未通过身份验证,我们将设置应用状态的路径。我会将您的ProtectedRoute修改为:

import { useEffect } from 'react';
import { Redirect, Route, RouteProps, useLocation } from 'react-router';
export type ProtectedRouteProps = {
isAuthenticated: boolean;
authenticationPath: string;
redirectPath: string;
setRedirectPath: (path: string) => void;
} & RouteProps;
export default function ProtectedRoute({isAuthenticated, authenticationPath, redirectPath, setRedirectPath, ...routeProps}: ProtectedRouteProps) {
const currentLocation = useLocation();
useEffect(() => {
if (!isAuthenticated) {
setRedirectPath(currentLocation.pathname);
}
}, [isAuthenticated, setRedirectPath, currentLocation]);
if(isAuthenticated && redirectPath === currentLocation.pathname) {
return <Route {...routeProps} />;
} else {
return <Redirect to={{ pathname: isAuthenticated ? redirectPath : authenticationPath }} />;
}
};

为了记住身份验证和重定向路径,我将基于以下模型创建一个上下文:

export type Session = {
isAuthenticated?: boolean;
redirectPath: string;
}
export const initialSession: Session = {
redirectPath: ''
};

根据这一点,上下文如下所示:

import { createContext, useContext, useState } from "react";
import { initialSession, Session } from "../models/session";
export const SessionContext = createContext<[Session, (session: Session) => void]>([initialSession, () => {}]);
export const useSessionContext = () => useContext(SessionContext);
export const SessionContextProvider: React.FC = (props) => {
const [sessionState, setSessionState] = useState(initialSession);
const defaultSessionContext: [Session, typeof setSessionState]  = [sessionState, setSessionState];
return (
<SessionContext.Provider value={defaultSessionContext}>
{props.children}
</SessionContext.Provider>
);
}

现在,需要将此上下文提供给应用:

import React from 'react';
import ReactDOM from 'react-dom';
import App from './containers/App';
import { SessionContextProvider } from './contexts/SessionContext';
import { BrowserRouter } from 'react-router-dom';
ReactDOM.render(
<React.StrictMode>
<BrowserRouter>
<SessionContextProvider>
<App />
</SessionContextProvider>
</BrowserRouter>
</React.StrictMode>,
document.getElementById('root')
);

在主容器中,您可以应用受保护的路由:

import ProtectedRoute, { ProtectedRouteProps } from "../components/ProtectedRoute";
import { useSessionContext } from "../contexts/SessionContext";
import { Route, Switch } from 'react-router';
import Homepage from "./Homepage";
import Dashboard from "./Dashboard";
import Protected from "./Protected";
import Login from "./Login";
export default function App() {
const [sessionContext, updateSessionContext] = useSessionContext();
const setRedirectPath = (path: string) => {
updateSessionContext({...sessionContext, redirectPath: path});
}
const defaultProtectedRouteProps: ProtectedRouteProps = {
isAuthenticated: !!sessionContext.isAuthenticated,
authenticationPath: '/login',
redirectPath: sessionContext.redirectPath,
setRedirectPath: setRedirectPath
};
return (
<div>
<Switch>
<Route exact={true} path='/' component={Homepage} />
<ProtectedRoute {...defaultProtectedRouteProps} path='/dashboard' component={Dashboard} />
<ProtectedRoute {...defaultProtectedRouteProps} path='/protected' component={Protected} />
<Route path='/login' component={Login} />
</Switch>
</div>
);
};

2021 年 3 月更新

我已经更新了上面的答案。React 在从外部组件设置状态时抛出错误。此外,当路径不受保护时/以前的解决方案也不起作用。此问题应已修复。

此外,我还为 React Router 6 创建了一个示例。

伙计我认为最好的方法是在这样的componentDidMount中使用history.push函数:

componentDidMount() {
if(isAuthenticated.auth) {
this.props.history.push('/profile')
}
else {
this.props.history.push('/login') 
}
}

在您的应用程序中.js

import { connect } from 'react-redux';
import { withRouter } from 'react-router-dom';
class App extends Component {
constructor(props) {
super(props)
this.state = {
urlToRedirect: null
}
}
componentWillReceiveProps(nextProps) {
if ( nextProps.location !== this.props.location && 
!this.props.isAuthenticated && 
this.props.history.action === 'REPLACE') {
this.setState({urlToRedirect: this.props.location.pathname});
}
}
}
const mapStateToProps = (state: ReduxStoreState) => ({
isAuthenticated: state.isAuthenticated
});
export default connect(mapStateToProps, null)(withRouter(App));

您可以使用 Redux 状态,然后访问该 URL,而不是使用 setState。

最新更新