我刚刚在我的 django 和 react 应用程序中实现了基于令牌的身份验证,现在我想确保未经授权的用户无法访问我的页面。我通过使用 PrivateRoute 尝试了这个。令人讨厌的是,当您重新加载页面时,它一直将我发送到登录页面,然后该页面识别出我已获得授权,并将我送回首页。
因此,出于某种原因,当我刷新页面时,将 isAuthenticated 变量设置为 false 一秒钟。我试图通过在我的 auth.state 中创建一个 isLoading 变量来解决这个问题。这应该识别出身份验证尚未加载,并且应该等待检查 isAuthenticated 状态。
但是,当我重新加载页面时,它仍然会登录,然后回到主页,因为它需要一段时间才能识别 isAuthenticated 变量。有谁知道为什么会发生这种情况?
这是我的 PrivateRoute 文件
import React, { useState } from 'react';
import { Redirect, Route } from 'react-router-dom'
import { connect } from 'react-redux';
const PrivateRoute = ({ component: Component, auth, ...rest }) => (
<Route
{...rest}
render={(props) => {
if (auth.isLoading) {
return <h2>Loading...</h2>;
} else if (!auth.isAuthenticated) {
return <Redirect to="/login" />;
} else {
return <Component {...props} />;
}
}}
/>
);
const mapStateToProps = (state) => ({
auth: state.auth,
});
export default connect(mapStateToProps)(PrivateRoute);
在reducers/auth 文件中我声明initialState 应该是isLoading = false,然后我声明当AUTHENTICATION_LOADING 被调用时isLoading 应该是true。当身份验证成功或失败时,isLoading 设置为 false。
const initialState = {
access: localStorage.getItem('access'),
refresh: localStorage.getItem('refresh'),
isAuthenticated: null,
user: null,
isLoading: false,
};
export default function(state = initialState, action) {
const { type, payload } = action;
switch(type) {
case AUTHENTICATED_LOADING:
return {
...state,
isLoading: true,
};
case AUTHENTICATED_SUCCESS:
return {
...state,
isAuthenticated: true,
isLoading: false,
}
case LOGIN_SUCCESS:
localStorage.setItem('access', payload.access);
localStorage.setItem('refresh', payload.refresh);
return {
...state,
isAuthenticated: true,
access: payload.access,
refresh: payload.refresh
}
case SIGNUP_SUCCESS:
return {
...state,
isAuthenticated: false
}
case USER_LOADED_SUCCESS:
return {
...state,
user: payload,
}
case AUTHENTICATED_FAIL:
return {
...state,
isAuthenticated: false,
isLoading: false,
}
case USER_LOADED_FAIL:
return {
...state,
user: null,
}
case LOGIN_FAIL:
case SIGNUP_FAIL:
case LOGOUT:
localStorage.removeItem('access');
localStorage.removeItem('refresh');
return {
...state,
access: null,
refresh: null,
isAuthenticated: false,
user: null
}
case PASSWORD_RESET_SUCCESS:
case PASSWORD_RESET_FAIL:
case PASSWORD_RESET_CONFIRM_SUCCESS:
case PASSWORD_RESET_CONFIRM_FAIL:
case ACTIVATION_SUCCESS:
case ACTIVATION_FAIL:
return {
...state
}
default:
return state
}
};
这是 actions/auth 文件的认证部分。在这个文件中,我首先发送 AUTHENTICATED_LOADING 变量,以确保在开始检查身份验证时 isLoading = true。
export const checkAuthenticated = () => async dispatch => {
dispatch({ type: AUTHENTICATED_LOADING });
if (localStorage.getItem('access')) {
const config = {
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
};
const body = JSON.stringify({ token: localStorage.getItem('access') });
try {
const res = await axios.post(`/auth/jwt/verify/`, body, config)
if (res.data.code !== 'token_not_valid') {
dispatch({
type: AUTHENTICATED_SUCCESS
});
} else {
dispatch({
type: AUTHENTICATED_FAIL
});
}
} catch (err) {
dispatch({
type: AUTHENTICATED_FAIL
});
}
} else {
dispatch({
type: AUTHENTICATED_FAIL
});
}
};