我怎样才能通过 isAuthenticated 让经过身份验证的组件路由到受保护的路由?
How can I pass isAuthenticated to let Authenticated Component route to protected route?
我正在通过 React Router v4 实现受保护的路由。
我试图将 "isAuthenticated" 值从 "Login" 组件传递到 "Authenticated" 组件,但我得到 "false" 值。
可能是我用错了方法,请问谁能帮忙解决这个问题?
我的代码如下:
Login.js提供"isAuthenticated"控制
import React, { Component } from 'react';
import { AUTH_TOKEN } from '../constants';
import { USERNAME } from '../constants';
import { graphql, compose } from 'react-apollo';
import { Row, Col, FormGroup, ControlLabel, Button } from 'react-bootstrap';
import gql from 'graphql-tag';
export const Auth = {
isAuthenticated: false,
authenticate(cb) {
this.isAuthenticated = true;
// setTimeout(cb, 100);
},
signout(cb) {
this.isAuthenticated = false;
// setTimeout(cb, 100);
}
};
class Login extends Component {
state = {
username: '',
password: '',
};
login = () => {
Auth.authenticate();
console.log(Auth.isAuthenticated);
};
render() {
return (
<Row>
<Col xs={12} sm={6} md={5} lg={4}>
<div className="Login">
<h4 className="page-header">Login</h4>
<form ref={form => (this.form = form)} onSubmit={event => event.preventDefault()}>
<FormGroup>
<ControlLabel>Username</ControlLabel>
<br />
<input
value={this.state.username}
onChange={e => this.setState({ username: e.target.value })}
type="text"
autoFocus
/>
</FormGroup>
<FormGroup>
<ControlLabel>Password</ControlLabel>
<br/>
<input
value={this.state.password}
onChange={e => this.setState({ password: e.target.value })}
type="password"
/>
</FormGroup>
<div onClick={() => {this._confirm(); this.login(); }}>
<Button type="submit" bsStyle="success">Login</Button>
</div>
</form>
</div>
</Col>
</Row>
)
};
_confirm = async () => {
const { username, password } = this.state;
const result = await this.props.loginMutation({
variables: {
username,
password,
},
});
const { token } = result;
this._saveUserData(token, username);
this.props.history.push(`/`);
}
_saveUserData = (token, username) => {
localStorage.setItem(AUTH_TOKEN, token);
localStorage.setItem(USERNAME, username);
}
};
const LOGIN_MUTATION = gql`
mutation LoginMutation($username: String!, $password: String!) {
loginMutation(username: $username, password: $password) {
token
}
}
`;
export default compose(
graphql(LOGIN_MUTATION, { name: 'loginMutation' }),
)(Login);
Authenticated.js 需要获取 "isAuthenticated" 值 (true) 才能呈现受保护的路由。
import React, { Component } from 'react';
import { Route, Redirect } from 'react-router-dom';
import { Auth } from '../pages/Login';
console.log(Auth.isAuthenticated);
class Authenticated extends Component {
render() {
const {
component: Component, exact, ...rest
} = this.props;
return (
<Route
{...rest}
exact={exact}
render={props => (
Auth.isAuthenticated ? (
<Component { ...props} />
) : (
<Redirect to="/login" />
))}
/>
);
}
}
export default Authenticated;
=== 解决方案 ===
Authenticated.js -> 从 localStorage
获取值
import React, { Component } from 'react';
import { Route, Redirect } from 'react-router-dom';
import { AUTH_TOKEN, IS_AUTHEN } from '../constants';
class Authenticated extends Component {
render() {
const {
component: Component, exact, ...rest
} = this.props;
const isAuthenticated = !!localStorage.getItem(IS_AUTHEN) && !!localStorage.getItem(AUTH_TOKEN);
console.log(isAuthenticated);
return (
<Route
{...rest}
exact={exact}
render={props => (
isAuthenticated ? (
<Component { ...props} />
) : (
<Redirect to="/login" />
))}
/>
);
}
}
export default Authenticated;
Login.js -> 使用 localStorage.setItem
存储值
import React, { Component } from 'react';
import { AUTH_TOKEN, USERNAME, IS_AUTHEN } from '../constants';
import { graphql, compose } from 'react-apollo';
import { Row, Col, FormGroup, ControlLabel, Button } from 'react-bootstrap';
import gql from 'graphql-tag';
class Login extends Component {
state = {
username: '',
password: '',
authenticated: false,
};
render() {
return (
<Row>
<Col xs={12} sm={6} md={5} lg={4}>
<div className="Login">
<h4 className="page-header">Login</h4>
<form ref={form => (this.form = form)} onSubmit={event => event.preventDefault()}>
<FormGroup>
<ControlLabel>Username</ControlLabel>
<br />
<input
value={this.state.username}
onChange={e => this.setState({ username: e.target.value })}
type="text"
autoFocus
/>
</FormGroup>
<FormGroup>
<ControlLabel>Password</ControlLabel>
<br/>
<input
value={this.state.password}
onChange={e => this.setState({ password: e.target.value })}
type="password"
/>
</FormGroup>
<div onClick={() => this._confirm()}>
<Button type="submit" bsStyle="success">Login</Button>
</div>
</form>
</div>
</Col>
</Row>
)
};
_confirm = async () => {
const { username, password } = this.state;
const result = await this.props.loginMutation({
variables: {
username,
password,
},
});
this.setState({ authenticated: true });
const { token } = result;
this._saveUserData(token, username, this.state.authenticated);
this.props.history.push(`/channel`);
}
_saveUserData = (token, username, authenticated) => {
localStorage.setItem(AUTH_TOKEN, token);
localStorage.setItem(USERNAME, username);
localStorage.setItem(IS_AUTHEN, authenticated);
}
};
const LOGIN_MUTATION = gql`
mutation LoginMutation($username: String!, $password: String!) {
loginMutation(username: $username, password: $password) {
token
}
}
`;
export default compose(
graphql(LOGIN_MUTATION, { name: 'loginMutation' }),
)(Login);
首先,在应用程序开始时(index.js),我检查令牌并在我的状态中设置 is_auth,像这样
<!-- ls is LocalStorageService for get and set from localStorage-->
if (ls.getUserDetails() && ls.getUserDetails().roles && ls.getUserDetails().roles.length) {
store.dispatch({ type: SET_USER_ROLE, role: ls.getUserDetails().roles[0] });
if (ls.getToken()) {
store.dispatch({ type: AUTHENTICATE_USER, auth: true });
}
}
else {
store.dispatch({ type: AUTHENTICATE_USER, auth: false });
}
然后,我制作了一个 AuthGuard 来验证登录状态,(通过将状态的身份验证映射到这个 class 的道具)
AuthGuard.js
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { push } from 'react-router-redux'
import { store } from '../stores/configureStore';
export default function (ComposedComponent) {
// If user not authenticated render out to root
class AuthGuard extends Component {
static contextTypes = {
router: React.PropTypes.object.isRequired
};
componentWillMount() {
if (!this.props.authenticated) {
//hashHistory.push('#/login');
store.dispatch(push('/login'));
}
}
componentWillUpdate(nextProps) {
if (!nextProps.authenticated) {
//hashHistory.push('#/login');
store.dispatch(push('/login'));
}
}
render() {
return <ComposedComponent {...this.props} />;
}
}
const mapStateToProps = (state) => ({
authenticated: state.auth.auth
});
return connect(mapStateToProps)(AuthGuard);
}
然后在我的 App.js 中进行路由选择,
App.js
<!--PROTECTED ROUTES GO AFTER '/app/'-->
<Route path={`${match.url}app`} component={authGuard(MainApp)} />
<!--UNPROTECTED ROUTES GO AFTER '/' LIKE BELOW-->
<Route exact path="/404" component={Page404} />
<Route exact path="/403" component={Page403} />
<Route exact path="/500" component={Page500} />
<Route exact path="/confirm-email" component={PageConfirmEmail} />
<Route exact path="/forgot-password" component={PageForgotPassword} />
<Route exact path="/fullscreen" component={PageFullscreen} />
<Route exact path="/lock-screen" component={PageLockScreen} />
<Route exact path="/login" component={PageLogin} />
<Route exact path="/sign-up" component={PageSignUp} />
如有任何问题,请在下方评论:)
我正在通过 React Router v4 实现受保护的路由。 我试图将 "isAuthenticated" 值从 "Login" 组件传递到 "Authenticated" 组件,但我得到 "false" 值。
可能是我用错了方法,请问谁能帮忙解决这个问题?
我的代码如下:
Login.js提供"isAuthenticated"控制
import React, { Component } from 'react';
import { AUTH_TOKEN } from '../constants';
import { USERNAME } from '../constants';
import { graphql, compose } from 'react-apollo';
import { Row, Col, FormGroup, ControlLabel, Button } from 'react-bootstrap';
import gql from 'graphql-tag';
export const Auth = {
isAuthenticated: false,
authenticate(cb) {
this.isAuthenticated = true;
// setTimeout(cb, 100);
},
signout(cb) {
this.isAuthenticated = false;
// setTimeout(cb, 100);
}
};
class Login extends Component {
state = {
username: '',
password: '',
};
login = () => {
Auth.authenticate();
console.log(Auth.isAuthenticated);
};
render() {
return (
<Row>
<Col xs={12} sm={6} md={5} lg={4}>
<div className="Login">
<h4 className="page-header">Login</h4>
<form ref={form => (this.form = form)} onSubmit={event => event.preventDefault()}>
<FormGroup>
<ControlLabel>Username</ControlLabel>
<br />
<input
value={this.state.username}
onChange={e => this.setState({ username: e.target.value })}
type="text"
autoFocus
/>
</FormGroup>
<FormGroup>
<ControlLabel>Password</ControlLabel>
<br/>
<input
value={this.state.password}
onChange={e => this.setState({ password: e.target.value })}
type="password"
/>
</FormGroup>
<div onClick={() => {this._confirm(); this.login(); }}>
<Button type="submit" bsStyle="success">Login</Button>
</div>
</form>
</div>
</Col>
</Row>
)
};
_confirm = async () => {
const { username, password } = this.state;
const result = await this.props.loginMutation({
variables: {
username,
password,
},
});
const { token } = result;
this._saveUserData(token, username);
this.props.history.push(`/`);
}
_saveUserData = (token, username) => {
localStorage.setItem(AUTH_TOKEN, token);
localStorage.setItem(USERNAME, username);
}
};
const LOGIN_MUTATION = gql`
mutation LoginMutation($username: String!, $password: String!) {
loginMutation(username: $username, password: $password) {
token
}
}
`;
export default compose(
graphql(LOGIN_MUTATION, { name: 'loginMutation' }),
)(Login);
Authenticated.js 需要获取 "isAuthenticated" 值 (true) 才能呈现受保护的路由。
import React, { Component } from 'react';
import { Route, Redirect } from 'react-router-dom';
import { Auth } from '../pages/Login';
console.log(Auth.isAuthenticated);
class Authenticated extends Component {
render() {
const {
component: Component, exact, ...rest
} = this.props;
return (
<Route
{...rest}
exact={exact}
render={props => (
Auth.isAuthenticated ? (
<Component { ...props} />
) : (
<Redirect to="/login" />
))}
/>
);
}
}
export default Authenticated;
=== 解决方案 ===
Authenticated.js -> 从 localStorage
获取值import React, { Component } from 'react';
import { Route, Redirect } from 'react-router-dom';
import { AUTH_TOKEN, IS_AUTHEN } from '../constants';
class Authenticated extends Component {
render() {
const {
component: Component, exact, ...rest
} = this.props;
const isAuthenticated = !!localStorage.getItem(IS_AUTHEN) && !!localStorage.getItem(AUTH_TOKEN);
console.log(isAuthenticated);
return (
<Route
{...rest}
exact={exact}
render={props => (
isAuthenticated ? (
<Component { ...props} />
) : (
<Redirect to="/login" />
))}
/>
);
}
}
export default Authenticated;
Login.js -> 使用 localStorage.setItem
存储值import React, { Component } from 'react';
import { AUTH_TOKEN, USERNAME, IS_AUTHEN } from '../constants';
import { graphql, compose } from 'react-apollo';
import { Row, Col, FormGroup, ControlLabel, Button } from 'react-bootstrap';
import gql from 'graphql-tag';
class Login extends Component {
state = {
username: '',
password: '',
authenticated: false,
};
render() {
return (
<Row>
<Col xs={12} sm={6} md={5} lg={4}>
<div className="Login">
<h4 className="page-header">Login</h4>
<form ref={form => (this.form = form)} onSubmit={event => event.preventDefault()}>
<FormGroup>
<ControlLabel>Username</ControlLabel>
<br />
<input
value={this.state.username}
onChange={e => this.setState({ username: e.target.value })}
type="text"
autoFocus
/>
</FormGroup>
<FormGroup>
<ControlLabel>Password</ControlLabel>
<br/>
<input
value={this.state.password}
onChange={e => this.setState({ password: e.target.value })}
type="password"
/>
</FormGroup>
<div onClick={() => this._confirm()}>
<Button type="submit" bsStyle="success">Login</Button>
</div>
</form>
</div>
</Col>
</Row>
)
};
_confirm = async () => {
const { username, password } = this.state;
const result = await this.props.loginMutation({
variables: {
username,
password,
},
});
this.setState({ authenticated: true });
const { token } = result;
this._saveUserData(token, username, this.state.authenticated);
this.props.history.push(`/channel`);
}
_saveUserData = (token, username, authenticated) => {
localStorage.setItem(AUTH_TOKEN, token);
localStorage.setItem(USERNAME, username);
localStorage.setItem(IS_AUTHEN, authenticated);
}
};
const LOGIN_MUTATION = gql`
mutation LoginMutation($username: String!, $password: String!) {
loginMutation(username: $username, password: $password) {
token
}
}
`;
export default compose(
graphql(LOGIN_MUTATION, { name: 'loginMutation' }),
)(Login);
首先,在应用程序开始时(index.js),我检查令牌并在我的状态中设置 is_auth,像这样
<!-- ls is LocalStorageService for get and set from localStorage-->
if (ls.getUserDetails() && ls.getUserDetails().roles && ls.getUserDetails().roles.length) {
store.dispatch({ type: SET_USER_ROLE, role: ls.getUserDetails().roles[0] });
if (ls.getToken()) {
store.dispatch({ type: AUTHENTICATE_USER, auth: true });
}
}
else {
store.dispatch({ type: AUTHENTICATE_USER, auth: false });
}
然后,我制作了一个 AuthGuard 来验证登录状态,(通过将状态的身份验证映射到这个 class 的道具)
AuthGuard.js
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { push } from 'react-router-redux'
import { store } from '../stores/configureStore';
export default function (ComposedComponent) {
// If user not authenticated render out to root
class AuthGuard extends Component {
static contextTypes = {
router: React.PropTypes.object.isRequired
};
componentWillMount() {
if (!this.props.authenticated) {
//hashHistory.push('#/login');
store.dispatch(push('/login'));
}
}
componentWillUpdate(nextProps) {
if (!nextProps.authenticated) {
//hashHistory.push('#/login');
store.dispatch(push('/login'));
}
}
render() {
return <ComposedComponent {...this.props} />;
}
}
const mapStateToProps = (state) => ({
authenticated: state.auth.auth
});
return connect(mapStateToProps)(AuthGuard);
}
然后在我的 App.js 中进行路由选择,
App.js
<!--PROTECTED ROUTES GO AFTER '/app/'-->
<Route path={`${match.url}app`} component={authGuard(MainApp)} />
<!--UNPROTECTED ROUTES GO AFTER '/' LIKE BELOW-->
<Route exact path="/404" component={Page404} />
<Route exact path="/403" component={Page403} />
<Route exact path="/500" component={Page500} />
<Route exact path="/confirm-email" component={PageConfirmEmail} />
<Route exact path="/forgot-password" component={PageForgotPassword} />
<Route exact path="/fullscreen" component={PageFullscreen} />
<Route exact path="/lock-screen" component={PageLockScreen} />
<Route exact path="/login" component={PageLogin} />
<Route exact path="/sign-up" component={PageSignUp} />
如有任何问题,请在下方评论:)