React.js身份验证在每次刷新时重定向到登录名
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了React.js身份验证在每次刷新时重定向到登录名相关的知识,希望对你有一定的参考价值。
[我注意到,当我刷新应用程序上的页面时,如果我通过了身份验证,它将闪到登录页面,然后转到仪表板。不管我刷新什么页面。
我很新,但我认为问题出在我的PrivateRoute.js逻辑中。它变为“ else:重定向到登录名”,但在登录页面上没有失败,因此它遵循“如果经过身份验证的重定向到仪表板”路线。
App.js:
import React, { Component, Fragment } from "react";
import ReactDOM from "react-dom";
import {
HashRouter as Router,
Route,
Switch,
Redirect
} from "react-router-dom";
import { Provider as AlertProvider } from "react-alert";
import AlertTemplate from "react-alert-template-basic";
import Header from "./layout/Header";
import Sidebar from "./layout/Sidebar";
import Home from "./common/Home";
import Profile from "./accounts/profile";
import Dashboard from "./leads/Dashboard";
import Alerts from "./layout/Alerts";
import Login from "./accounts/Login";
import Register from "./accounts/Register";
import PrivateRoute from "./common/PrivateRoute";
import { Provider } from "react-redux";
import store from "../store";
import { loadUser } from "../actions/auth";
// Alert Options
const alertOptions = {
timeout: 3000,
position: "top center"
};
class App extends Component {
componentDidMount() {
store.dispatch(loadUser());
}
render() {
return (
<Provider store={store}>
<AlertProvider template={AlertTemplate} {...alertOptions}>
<Router>
<Fragment>
<Header />
<Alerts />
<div className="container-fluid page-body-wrapper">
<Sidebar />
<Switch>
<Route exact path="/" component={Home} />
<PrivateRoute exact path="/dashboard" component={Dashboard} />
<PrivateRoute exact path="/profile" component={Profile} />
<Route exact path="/login" component={Login} />
<Route exact path="/register" component={Register} />
</Switch>
</div>
</Fragment>
</Router>
</AlertProvider>
</Provider>
);
}
}
ReactDOM.render(<App />, document.getElementById("app"));
PrivateRoute.js
import React from "react";
import { Route, Redirect } from "react-router-dom";
import { connect } from "react-redux";
import PropType from "prop-types";
const PrivateRoute = ({ component: Component, auth, path, ...rest }) => (
<Route
path={path}
{...rest}
render={props => {
if (auth.isLoading) {
return <h2>Loading...</h2>;
} else if (auth.isAuthenticated) {
return <Component {...props} />;
} else {
return <Redirect to="/login" />;
}
}}
/>
);
const mapStateToProps = state => ({
auth: state.auth
});
export default connect(mapStateToProps)(PrivateRoute);
Login.js
import React, { Component } from "react";
import { Link, Redirect } from "react-router-dom";
import { connect } from "react-redux";
import PropTypes from "prop-types";
import { login } from "../../actions/auth";
export class Login extends Component {
state = {
username: "",
password: ""
};
static propTypes = {
login: PropTypes.func.isRequired,
isAuthenticated: PropTypes.bool
};
onSubmit = e => {
e.preventDefault();
this.props.login(this.state.username, this.state.password);
};
onChange = e => this.setState({ [e.target.name]: e.target.value });
render() {
{
/*if (this.props.isAuthenticated) {
return <Redirect to="/dashboard" />;
}*/
}
const { username, password } = this.state;
return (
<div className="col-md-12 m-auto" style={{ maxWidth: 500 }}>
<div className="card card-body mt-5">
<h2 className="text-center py-3">Login to Reely.io</h2>
<form onSubmit={this.onSubmit}>
<div className="form-group">
<label>Username</label>
<input
type="text"
className="form-control"
name="username"
onChange={this.onChange}
value={username}
/>
</div>
<div className="form-group">
<label>Password</label>
<input
type="password"
className="form-control"
name="password"
onChange={this.onChange}
value={password}
/>
</div>
<div className="form-group">
<button type="submit" className="btn btn-primary">
Login
</button>
</div>
<p>
Need an account? <Link to="/register">Register</Link>
</p>
</form>
</div>
</div>
);
}
}
const mapStateToProps = state => ({
isAuthenticated: state.auth.isAuthenticated
});
export default connect(mapStateToProps, { login })(Login);
auth.js-操作
import axios from "axios";
import { returnErrors } from "./messages";
import {
USER_LOADED,
USER_LOADING,
AUTH_ERROR,
LOGIN_SUCCESS,
LOGIN_FAIL,
LOGOUT_SUCCESS,
REGISTER_SUCCESS,
REGISTER_FAIL
} from "./types";
// CHECK TOKEN & LOAD USER
export const loadUser = () => (dispatch, getState) => {
// User Loading
dispatch({ type: USER_LOADING });
axios
.get("/api/auth/user", tokenConfig(getState))
.then(res => {
dispatch({
type: USER_LOADED,
payload: res.data
});
})
.catch(err => {
dispatch(returnErrors(err.response.data, err.response.status));
dispatch({
type: AUTH_ERROR
});
});
};
// LOGIN USER
export const login = (username, password) => dispatch => {
// Headers
const config = {
headers: {
"Content-Type": "application/json"
}
};
// Request Body
const body = JSON.stringify({ username, password });
axios
.post("/api/auth/login/", body, config)
.then(res => {
dispatch({
type: LOGIN_SUCCESS,
payload: res.data
});
})
.catch(err => {
dispatch(returnErrors(err.response.data, err.response.status));
dispatch({
type: LOGIN_FAIL
});
});
};
// REGISTER USER
export const register = ({ username, password, email }) => dispatch => {
// Headers
const config = {
headers: {
"Content-Type": "application/json"
}
};
// Request Body
const body = JSON.stringify({ username, password, email });
axios
.post("/api/auth/register/", body, config)
.then(res => {
dispatch({
type: REGISTER_SUCCESS,
payload: res.data
});
})
.catch(err => {
dispatch(returnErrors(err.response.data, err.response.status));
dispatch({
type: REGISTER_FAIL
});
});
};
// LOGOUT USER
export const logout = () => (dispatch, getState) => {
axios
.post("/api/auth/logout/", null, tokenConfig(getState))
.then(res => {
dispatch({
type: LOGOUT_SUCCESS
});
})
.catch(err => {
dispatch(returnErrors(err.response.data, err.response.status));
});
};
// SETUP CONFIG W/ TOKEN - Helper Function
export const tokenConfig = getState => {
// Get token from state
const token = getState().auth.token;
// Headers
const config = {
headers: {
"Content-Type": "application/json"
}
};
// If token, add to header config
if (token) {
config.headers["Authorization"] = `Token ${token}`;
}
return config;
};
types.js
export const GET_LEADS = "GET_LEADS";
export const DELETE_LEADS = "DELETE_LEADS";
export const ADD_LEAD = "ADD_LEAD";
export const GET_ERRORS = "GET_ERRORS";
export const CREATE_MESSAGE = "CREATE_MESSAGE";
export const USER_LOADING = "USER_LOADING";
export const USER_LOADED = "USER_LOADED";
export const AUTH_ERROR = "AUTH_ERROR";
export const LOGIN_SUCCESS = "LOGIN_SUCCESS";
export const LOGIN_FAIL = "LOGIN_FAIL";
export const LOGOUT_SUCCESS = "LOGOUT_SUCCESS";
export const REGISTER_SUCCESS = "REGISTER_SUCCESS";
export const REGISTER_FAIL = "REGISTER_FAIL";
auth.js-减速器
import {
USER_LOADED,
USER_LOADING,
AUTH_ERROR,
LOGIN_SUCCESS,
LOGIN_FAIL,
LOGOUT_SUCCESS,
REGISTER_SUCCESS,
REGISTER_FAIL
} from "../actions/types";
const initialState = {
token: localStorage.getItem("token"),
isAuthenticated: null,
isLoading: false,
user: null
};
export default function(state = initialState, action) {
switch (action.type) {
case USER_LOADING:
return {
...state,
isLoading: true
};
case USER_LOADED:
return {
...state,
isAuthenticated: true,
isLoading: false,
user: action.payload
};
case LOGIN_SUCCESS:
case REGISTER_SUCCESS:
localStorage.setItem("token", action.payload.token);
return {
...state,
...action.payload,
isAuthenticated: true,
isLoading: false
};
case AUTH_ERROR:
case LOGIN_FAIL:
case LOGOUT_SUCCESS:
case REGISTER_FAIL:
localStorage.removeItem("token");
return {
...state,
token: null,
user: null,
isAuthenticated: false,
isLoading: false
};
default:
return state;
}
}
答案
问题来自initialState
。您需要将isLoading
设置为true
。
const PrivateRoute = ({ component: Component, auth, path, ...rest }) => (
<Route
path={path}
{...rest}
render={props => {
if (auth.isLoading) {
// If initialState.isLoading = false,
// then your application will skip this step
// (just after a refresh)
return <h2>Loading...</h2>;
} else if (auth.isAuthenticated) {
// But because USER_LOADING is not triggered yet,
// your are not authenticated !
return <Component {...props} />;
} else {
// Then you drop here
return <Redirect to="/login" />;
}
}}
/>
);
在我当前的项目中,我使用initialized
变量(在开始时为假)管理了这种情况:
import React, {FC} from "react"
import {RouteProps, Route, Redirect} from "react-router-dom"
import {useAuthState} from "./context"
const PrivateRoute: FC<RouteProps> = props => {
const auth = useAuthState()
if (!auth.initialized) {
return null
}
if (!auth.authenticated) {
return <Redirect to="/login" />
}
return <Route {...props} />
}
export default PrivateRoute
以上是关于React.js身份验证在每次刷新时重定向到登录名的主要内容,如果未能解决你的问题,请参考以下文章