在尝试通过登录对我的react应用进行身份验证后,我试图找出如何将其重定向到正确的页面。
这是我的App.js文件,该文件带有路由(没有导入):
ReactDOM.render((
<Provider store={store}>
<Router history={history}>
<Switch>
<PrivateRoute path="/test" component={Test} />
<Route path="/login" component={Login} />
<PrivateRoute path="/" render={() => <h1>Welcome</h1>} />
</Switch>
</Router>
</Provider>
), document.getElementById('root'));
我正在使用PrivateRoute组件来确保对私有路由进行身份验证:
class PrivateRoute extends Route {
render() {
const { component: Component, isAuthenticated } = this.props;
let propsCopy = Object.assign({}, this.props);
delete propsCopy.component;
delete propsCopy.isAuthenticated;
return (
isAuthenticated
? <Component {...propsCopy} />
: <Redirect to={{
pathname: LOGIN_PATH,
state: { from: this.props.location }
}} />
);
}
}
/**
* Maps properties from Redux store to this component.
* @param {Object} state Redux object
* @return {Object} mapper properties
*/
function mapStateToProps(state) {
// pull out auth element from Redux store state
const { auth } = state;
// extract authenticated element from auth object
const { isAuthenticated } = auth;
return {
isAuthenticated
}
}
export default connect(mapStateToProps)(PrivateRoute);
重定向到的“我的登录”组件(为示例而简化:
class LoginForm extends Component {
constructor() {
super();
this.state = {
email: '',
password: '',
}
this.handleFormSubmit = this.handleFormSubmit.bind(this);
}
handleFormSubmit(event) {
//event.preventDefault();
const validation = this.validator.validate(this.state);
this.setState({ validation });
this.submitted = true;
if (validation.isValid) {
// submit form here
this.props.loginUser({
email: this.state.email,
password: this.state.password
});
}
}
render() {
return (
// My login FROM code here
)
}
}
function mapStateToProps(state) {
return {
isFetching: state.auth.isFetching,
loginError: state.auth.loginError,
isAuthenticated: state.auth.isAuthenticated
};
}
function mapDispatchToProps(dispatch, props, state) {
return {
loginUser: (credentials) => {
dispatch(loginUser(credentials));
},
};
}
export default connect(mapStateToProps, mapDispatchToProps)(LoginForm);
现在,如果LoginForm
为false,它将在重定向到isAuthenticated
组件的地方起作用。我可以将登录表单提交到我的登录服务,并收到成功回复并设置isAuthenticated
。
我的问题是如何重定向到原始路线?重定向通常在哪里进行?我假设它从未在reducer中完成,所以必须在LoginForm
组件中完成,对吗?
我知道有很多资源可以讨论整个登录流程,但是我找不到解决该问题的资源(这让我感到惊讶)。每个人都重定向到特定页面(“ /”,“ / home”等),但是我如何捕获并重定向到原始路由。
答案 0 :(得分:1)
由于PrivateRoute
为from
而发生重定向时,isAuthenticated
组件正在false
中存储先前的路由。 LoginForm
为isAuthenticated
时,可以在true
中使用它来重定向用户。只需从from
中提取this.props.location.state
,然后将其与Redirect
中的react-router-dom
组件结合使用。如果您登录this.props.location.state.from
,将看到属性pathname
包含用户试图以未经身份验证的状态进入的字符串路由路径,一旦身份验证成功,该路径可用于重定向它们。
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { Redirect, withRouter } from 'react-router-dom';
class LoginForm extends Component {
constructor(props) {
super(props);
this.state = {
email: '',
password: '',
}
this.handleFormSubmit = this.handleFormSubmit.bind(this);
}
handleFormSubmit(event) {
event.preventDefault();
const validation = this.validator.validate(this.state);
this.setState({ validation });
this.submitted = true;
if (validation.isValid) {
// submit form here
this.props.loginUser({
email: this.state.email,
password: this.state.password
});
}
}
render() {
const { from } = this.props.location.state || { from: { pathname: "/" } };
const { isAuthenticated } = this.props;
if (isAuthenticated) {
return <Redirect to={from} />;
}
return (
{* login from code *}
);
}
}
function mapStateToProps(state) {
return {
isFetching: state.auth.isFetching,
loginError: state.auth.loginError,
isAuthenticated: state.auth.isAuthenticated
};
}
function mapDispatchToProps(dispatch, props, state) {
return {
loginUser: (credentials) => {
dispatch(loginUser(credentials));
},
};
}
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(LoginForm));
您可能需要很好地更新PrivateRoute
组件,以确保它返回一个Route
,这与react-router-dom
example是一致的:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { Redirect, withRouter } from 'react-router-dom';
const PrivateRoute = ({ component: Component, ...rest }) => (
<Route {...rest} render={props =>
rest.isAuthenticated ? (
<Component {...props} />
) : (
<Redirect
to={{
pathname: LOGIN_PATH,
state: { from: props.location }
}}
/>
)
}
/>
);
const mapStateToProps = ({ auth: { isAuthenticated } }) => ({ isAuthenticated });
export default withRouter(connect(mapStateToProps)(PrivateRoute));
我创建了一个简化的StackBlitz,演示了实际的功能。
希望有帮助!
答案 1 :(得分:1)
@Alexander和@ bos570首先,我非常感谢您这样做的方式。有更好的方法,但是这里是一种以受控方式构建它的实现:
在您的index.js
中:
import React from 'react';
import ReactDOM from 'react-dom';
import './styles.scss'; // it depends what styles you're using css,scss,jss
import App from './App';
ReactDOM.render(<App />, document.getElementById('app'));
在您的App.js
中:
class App extends Component {
state = {
isAuthenticated: false,
};
componentDidMount(){
//call authentication API here
// setState isAuthentication to true upon authentication success
}
render(){
return(
<Provider store={store}>
<BrowserRouter>{isAuthenticated ? <Routes /> : <Login />}</BrowserRouter>
</Provider>
)}
您的Routes.js
将在Switch
中包含所有路由,除非API响应成功,否则它将一直显示加载屏幕。然后您将重新路由到基本的登录页面。
即使您已完成代码拆分,也不会在身份验证失败后从main.bundle.js上从网络下载任何捆绑软件。
当人们使用Redux
就像编程中的各行各业时,我会看到人们。我知道您将来的身份验证实现将为您提供一个refreshToken,这就是身份验证API为我们所做的。您可以将其存储在localStorage中,如果有人在任何时候刷新浏览器,您都无法将其保留在redux中,因为我们知道redux在浏览器刷新后会丢失状态,因此需要这样做 localStorage 表演。明智地使用它,我真的很想与你们所有人进行转换,我们如何才能使其变得更好。
我希望这会对您有所帮助。并且也许redux将并排用于身份验证。在应用程序中实现身份验证时,我度过了愉快的时光。 欢呼声
已编辑保持原样。但是我们需要知道在哪一点,您需要 redux,localStorage,Context API