问题
I'm implementing authentication into my app, the issue I am having is on refresh the state is not persistent so I get redirected back to the login screen. How can I use React Hooks to check if there is an authToken in local storage
to keep me logged in on refresh.
This is My Protected Route That checks for auth tokens
<Route
{...rest}
render={
props=>
authTokens ? (
<Component {...props}/>
) : (
<Redirect
to ={
{
pathname: '/login',
state: {
from: props.location
}
}
}
/>
This is my Login page Function
function Login(props) {
const [isLoggedIn, setLoggedIn] = useState(false);
const [isError, setIsError] = useState(false);
const [firstName, setUserName] = useState("");
const [password, setPassword] = useState("");
const { setAuthTokens } = useAuth();
function postLogin() {
axios.post("http://10.6.254.22:5000/userinformation/login", {
firstName,
password
}).then(result => {
if (result.status === 200) {
console.log('You have been logged in as user: ' +result.data[0].firstName)
setAuthTokens(result.data);
setLoggedIn(true);
} else {
setIsError(true);
}
}).catch(e => {
setIsError(true);
});
}
if (isLoggedIn) {
return <Redirect to="/" />;
}
Below is my Hook that contains the state
const [authTokens, setAuthTokens] = useState();
const setTokens = (data) => {
localStorage.setItem("authTokens", JSON.stringify(data));
setAuthTokens(data);
}
useEffect(()=> {
let jsonToken = localStorage.getItem('authTokens', JSON.stringify(authTokens))
console.log('JSON TOKEN -----' + jsonToken)
setAuthTokens(jsonToken)
})
How can i set the state authTokens with the local storage
variable on load so that when I refresh the state isnt empty so i dont get logged out on page reload. Also to mention The context provider is set up as so:
<AuthContext.Provider value={{ authTokens, setAuthTokens: setTokens}}>
<ProtectedRoute path="/" exact component={ProfileBox}/>
</AuthContext.Provider>
回答1:
The problem is that authTokens
is undefined
when your component mounts, so the logic of your Protected route is evaluating to the Redirect
portion of your code, causing the redirection to /login
.
React will remove componentWillMount
hook, so, the solution I found to this specific problem, is to check also for the token in the localStorage
, instead of just checking for the state authTokens
.
This way, your code will be able to evaluate that you have the token (even before the first component update).
The code of your Protected Route
may look like this:
<Route
{...rest}
render={
props=>
(authTokens || localStorage.getItem("authTokens")) ? (
<Component {...props}/>
) : (
<Redirect
to ={
{
pathname: '/login',
state: {
from: props.location
}
}
}
/>
Other possible solutions are:
- Using Context
- Using Redux
But I think that if you just want to protect private routes, this solution is sufficient
回答2:
You can create a hook that checks that the localstorage
contains the token, if it doesn't exist the user isn't authenticated, so you can redirect him to logIn, else the user can access the ProtectedRoutes
.
Maybe you can reuse your hook inside the ProtectedRoute
component and handle it just there.
ProtectedRoute
Lets say that your component Login is the page that you want to redirect if the user isn't auth
. And lets say that you are using react-router
or something to handle the routes and redirections.
const ProtectedRoute = ({component, ...options}) => {
const [isAuth ] = useAuth();
let conditionalComponent = Login;
if( isAuth ){
conditionalComponent = component;
}
return <Route {...options} component={conditionalComponent} />
}
useAuth
const useAuth = () => {
let [isAuth, handleAuthorized] = useState(false);
useEffect( () => {
if( checkLocalStorageToken() ){
handleAuthorized( true );
}
else {
handleAuthorized(false)
}
return [ isAuth ]
}, [ checkLocalStorageToken() ]);
}
I've been used this pattern and works good, i hope that i can share the main idea so you can implement it in your case.
来源:https://stackoverflow.com/questions/58751020/how-do-i-keep-state-persistant-using-local-storage-react-hooks-and-context-pro