“登录”并尝试执行一些重定向后遇到问题。此问题在API响应之后。我正在将CoreUI Pro与React Router v4一起使用。
在登录组件中重定向时,出现此错误
map1 = Map<MyModel, List<String>>();
map2 = Map<String, String>();
Map<MyModel, List<String>> map3 = Stream.of(map1, map2)
.flatMap(map -> map.entrySet().stream())
.collect(Collectors.toMap(
Map.Entry::getKey,
Map.Entry::getValue,
(v1, v2) -> v1
)
);
然后停在那里,不会继续进入仪表板。
当尝试在父组件(应用程序)中重定向时,“什么也没有发生”
登录组件仍将数据发送到App中的handleLogin绑定,并且handleLogin也会执行所需的操作,但不会在子Switch部分中重定向,如下所示。
注意,评论是我到目前为止尝试过的事情。
组件应用(父级)
index.js:2178 Warning: You tried to redirect to the same route you're currently on: "/authenticated"
组件登录(应用程序的子级)
import React, { Component } from 'react';
import { HashRouter, Route, Switch, Redirect } from 'react-router-dom';
import './App.css';
// Styles
// CoreUI Icons Set
import '@coreui/icons/css/coreui-icons.min.css';
// Import Flag Icons Set
import 'flag-icon-css/css/flag-icon.min.css';
// Import Font Awesome Icons Set
import 'font-awesome/css/font-awesome.min.css';
// Import Simple Line Icons Set
import 'simple-line-icons/css/simple-line-icons.css';
// Import Main styles for this application
import './scss/style.css'
// Containers
import { DefaultLayout } from './containers';
// Pages
import { Login, Page404, Page500, Register } from './views/Pages';
class App extends Component {
constructor(props) {
super(props);
this.state = {
authenticated: false
};
this.handleLogin = this.handleLogin.bind(this);
}
componentDidUpdate(prevProps, prevState) {
console.log(prevProps, prevState);
console.log(localStorage.getItem('authenticated'));
return localStorage.getItem('authenticated') === true
}
handleLogin(jwtToken, authResult) {
console.log(jwtToken, authResult);
localStorage.setItem('jwtToken', jwtToken);
localStorage.setItem('authenticated', authResult);
this.setState({ authenticated: true });
}
render() {
const ProtectedRoute = ({ component: Component, ...rest }) => (
<Route {...rest} render={(props) => (
localStorage.getItem('authenticated') === true
? <Component {...props} />
: () => {
console.log('failed to login');
return <Redirect to={{
pathname: '/login',
state: { from: props.location }
}} />
}
)} />
);
return (
<HashRouter>
<Switch>
<Route exact path="/login" name="Login Page" component={Login} />
<Route exact path="/register" name="Register Page" component={Register} />
<Route exact path="/404" name="Page 404" component={Page404} />
<Route exact path="/500" name="Page 500" component={Page500} />
<Route path="/" name="Login Page" render={(props) => {
return(<Login {...props} handleLogin={this.handleLogin}/>)
}}/>
<ProtectedRoute exact path="/authenticated" name="Dashboard" component={DefaultLayout} />
/*{this.state.authenticated ? <Redirect to='/authenticated' /> : ''} */
</Switch>
</HashRouter>
);
}
}
export default App;
编辑
此外,/ authenticated之后,还应该像下面那样呈现仪表板。它不会被渲染。
console.log在import React, { Component } from 'react';
import { Button, Card, CardBody, CardGroup, Col, Container, Input, InputGroup, InputGroupAddon, InputGroupText, Row } from 'reactstrap';
import axios from 'axios';
import { Redirect, Switch } from 'react-router-dom';
//import jwtDecode from 'jwt-decode';
const apiUrl = 'http://localhost:3015';
const emailRegex = 'blah blah blah';
const brandDanger = '#f86c6b';
const errorStyle = {
marginLeft: '1em',
marginTop: '-1em',
color: brandDanger,
fontStyle: 'italic',
};
class Login extends Component {
constructor(props) {
super(props);
// initial state of things
this.state = {
email: '',
password: '',
isValidEmail: null,
isValidPassword: null,
disableLoginButton: true,
authenticated: false
};
this.handleChange = this.handleChange.bind(this);
this.submitRequest = this.submitRequest.bind(this);
}
handleChange(e) {
this.setState({
[e.target.name]: e.target.value
});
if (emailRegex.test(this.state.email) && this.state.password.length > 0) {
this.setState({
isValidEmail: true,
isValidPassword: true,
disableLoginButton: false
});
} else {
this.setState({
isValidEmail: false,
isValidPassword: false,
disableLoginButton: true
});
}
}
async submitRequest() {
this.setState({disableLoginButton: !this.state.disableLoginButton});
const login = await axios.post(`${apiUrl}/api/auth/login`, {email: this.state.email, password: this.state.password});
try {
if (login.data.authentication) {
this.props.handleLogin(login.data.token, login.data.authentication);
this.setState({ authenticated: true });
}
} catch (err) {
console.log(err)
}
}
render() {
//console.log(`thisprops = \n${JSON.stringify(this.props)}`);
if (this.state.authenticated) {
return <Redirect to='/authenticated'/>
}
return (
<div className="app flex-row align-items-center">
<Container>
<Row className="justify-content-center">
<Col md="8">
<CardGroup>
<Card className="p-4">
<CardBody>
<h1>Login</h1>
<p className="text-muted">Sign In to your account</p>
<InputGroup className="mb-3">
<InputGroupAddon addonType="prepend">
<InputGroupText>
<i className="icon-user"></i>
</InputGroupText>
</InputGroupAddon>
<Input
type="text"
placeholder="Email"
name="email"
onChange={this.handleChange}
/>
</InputGroup>
{this.state.isValidEmail === null ? '' : !this.state.isValidEmail ? <p style={errorStyle}>Email is not valid.</p> : '' }
<InputGroup className="mb-4">
<InputGroupAddon addonType="prepend">
<InputGroupText>
<i className="icon-lock"></i>
</InputGroupText>
</InputGroupAddon>
<Input
type="password"
placeholder="Password"
name="password"
onChange={this.handleChange}
/>
</InputGroup>
{this.state.isValidPassword === null ? '' : !this.state.isValidPassword ? <p style={errorStyle}>Password is required.</p> : '' }
<Row>
<Col xs="6">
<Button
color="primary"
className="px-4"
onClick={this.submitRequest}
disabled={this.state.disableLoginButton}
>Login</Button>
</Col>
<Col xs="6" className="text-right">
<Button color="link" className="px-0">Forgot password?</Button>
</Col>
</Row>
</CardBody>
</Card>
<Card className="text-white bg-primary py-5 d-md-down-none" style={{ width: 44 + '%' }}>
<CardBody className="text-center">
<div>
<h2>Sign up</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut
labore et dolore magna aliqua.</p>
<Button color="primary" className="mt-3" active>Register Now!</Button>
</div>
</CardBody>
</Card>
</CardGroup>
</Col>
</Row>
<Row className="justify-content-center">
<Col md="8">
<span className="ml-1">© </span>
</Col>
</Row>
</Container>
</div>
);
}
}
export default Login;
组件DefaultLayout(应用程序的子级?)
class DefaultComponent extends Component {...}
答案 0 :(得分:0)
在重新构建项目并执行我的较早方法之一后,解决了该问题。
客户端身份验证流的工作方法。
在父级App Component
中,应/
的请求,响应路由器以PrivateRoute Component
进行响应,该协商协商用户是否登录,并以要求/重定向登录或继续进行响应到仪表板。
如果需要登录,则会渲染Login Component
并将状态authenticated
设置为false。如果来自API的成功登录响应,则将状态authenticated
设置为true。这将导致该应用使用<Redirect .../>
重新呈现,并再次点击位于父App Component
中的PrivateRoute。
从此处开始,协商PrivateRoute
中的正确身份验证,然后按预期进行。参见下面的src。
应用组件
import React, { Component } from 'react';
import { HashRouter, Route, Switch, Redirect } from 'react-router-dom';
import jwtDecode from 'jwt-decode';
import ...
class App extends Component {
render() {
const checkAuth = () => {
if (!localStorage.getItem('token') || localStorage.getItem('token') === false) {
return false;
}
else if (jwtDecode(localStorage.getItem('token')).exp < Date.now() / 1000) {
localStorage.setItem('token', false);
return false;
}
console.log(jwtDecode(localStorage.getItem('token')).exp);
console.log(Date.now() / 1000);
console.log(jwtDecode(localStorage.getItem('token')));
return true;
};
const PrivateRoute = ({ component: Component, ...rest }) => (
<Route {...rest} render={(props) => (
checkAuth()
? <Component {...props} />
: <Redirect to='/login' />
)} />
)
return (
<HashRouter>
<Switch>
<Route exact path="/login" name="Login Page" component={Login} />
<Route exact path="/register" name="Register Page" component={Register} />
<Route exact path="/404" name="Page 404" component={Page404} />
<Route exact path="/500" name="Page 500" component={Page500} />
<PrivateRoute path="/" name="Home" component={DefaultLayout} />
</Switch>
</HashRouter>
);
}
}
export default App;
登录组件
import React, { Component } from 'react';
import axios from 'axios';
import { Redirect } from 'react-router-dom';
import ...
class Login extends Component {
constructor(props) {
super(props);
// initial state of things
this.state = {
...
authenticated: false // set auth to false. If login request is successful, set to true which will allow the Redirect below to work.
};
this.handleChange = this.handleChange.bind(this);
this.submitRequest = this.submitRequest.bind(this);
}
handleChange(e) {
this.setState({
[e.target.name]: e.target.value
});
if (emailRegex.test(this.state.email) && this.state.password.length > 0) {
this.setState({
isValidEmail: true,
isValidPassword: true,
disableLoginButton: false
});
} else {
this.setState({
isValidEmail: false,
isValidPassword: false,
disableLoginButton: true
});
}
}
submitRequest = async() => {
this.setState({disableLoginButton: !this.state.disableLoginButton});
const login = await axios.post(`${apiUrl}/api/auth/login`, {email: this.state.email, password: this.state.password});
try {
if (login.data.authentication) {
localStorage.setItem('token', login.data.token);
// successful login, set state of authenticated to true
this.setState({ authenticated: !this.state.authenticated });
}
} catch (err) {
console.log(err)
}
}
render() {
if (this.state.authenticated) {
return <Redirect to='/'/> // Request '/' route from react router if auth'd.
}
return (
<div className="app flex-row align-items-center">
... Login Form
</div>
);
}
}
export default Login;
DefaultLayout /仪表板组件
import React, { Component } from 'react';
import { Redirect, Route, Switch } from 'react-router-dom';
import navigation from '../../_nav';
// routes config
import routes from '../../routes';
import ...
class DefaultLayout extends Component {
render() {
return (
<div className="app">
...
<Container fluid>
<Switch>
{routes.map((route, idx) => {
return route.component ? (<Route key={idx} path={route.path} exact={route.exact} name={route.name} render={props => (
<route.component {...props} />
)} />)
: (null);
},
)}
<Redirect from="/" to="/dashboard" /> // To dashboard!
</Switch>
...
</div>
);
}
}
export default DefaultLayout;