I have a problem with understanding why my app works kinda odd. When I try to reach any site on my page by clicking a link button in navbar, it navigates me there without any problems, like when I click "My account", the URL changes to "http://localhost:3000/my_account" and everything works just fine. In this place I have to mention that "/my_account" is a protected route - user has to be logged in to reach it, when he is not logged in - he gets send to the homepage. So now the problem is that when user is logged in and tries to reach the protected route like "http://localhost:3000/my_account" by entering this URL and loading page - he is treated like a non-logged user and gets redirected to the homepage. And after he is redirected there and tries to reach this site by clicking the navbar link, he can enter this page - he is logged in. My expected result is that user can enter any URL on the site and react should check PROPRERLY if he is logged in in both cases - either when clicking a link on site or by providing a url. Can anyone tell me where do I make mistake?
UserAccount (/my_account) is a simple component:
import React, { Component } from 'react'
export class UserAccount extends Component {
render() {
return (
<div>
UserAccount
</div>
)
}
}
export default UserAccount
In router in App.js I declare this route as:
<PrivateRoute path="/my_account" exact component={UserAccount}></PrivateRoute>
And the PrivateRoute is a functional component:
import React from 'react'
import {Route, Redirect} 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"></Redirect>
}
else{
return <Component {...props}/>
}
}}></Route>
)
const mapStateToProps = state =>({
auth: state.auth
})
export default connect(mapStateToProps,null)(PrivateRoute);
My state in auth.js (reducer):
const initialState = {
access: localStorage.getItem('access'),
refresh: localStorage.getItem('refresh'),
isAuthenticated: null,
isLoading : false,
user: null,
requestSent: false,
payload: null,
message: null
}
And after successful login, state changes as follows:
switch(type){
case AUTHENTICATED_SUCCESS:
return {
...state,
isAuthenticated: true
}
case LOGIN_SUCCESS:
localStorage.setItem('access', payload.access);
return{
...state,
isAuthenticated: true,
access: payload.access,
refresh: payload.refresh
}
And login function from auth.js actions:
export const login = (email, password) => async dispatch =>{
const config = {
headers: {
'Content-Type': 'application/json'
}
};
const body = JSON.stringify({email, password});
try{
const res = await axios.post(`${process.env.REACT_APP_API_URL}/auth/jwt/create/`, body, config);
dispatch({
type: LOGIN_SUCCESS,
payload: res.data
})
dispatch(load_user());
dispatch(createMessage({logged_in_successfully: "You are now logged in."}))
} catch (err) {
dispatch({
type: LOGIN_FAIL,
payload: err
})
const errors = {msg: err.response.data, status: err.response.status}
dispatch({
type:GET_ERRORS,
payload: errors
})
}
};
Thanks for your time reading that and I am hoping for some help.
CodePudding user response:
import React, { useEffect } from 'react'
import { useNavigate } from 'react-router-dom'
export default function UserAccount() {
let navigate = useNavigate();
useEffect(() => {
let authToken = sessionStorage.getItem('access')
// if user is not authed, redirect user to login page
if (!authToken) {
navigate('/login')
}
}, [])
return (
<div>
Home Page
</div>
)
}
Answer uses functional component and react router v6 . If you provide which version of react-router you're using I can update my answer
You forgot to add condition for checking weather user is authed or no. For this, you need to check inside UserAccount Page. I provided snippet. Condition should be write inside useEffect
in functional component. Inside class based component inside componentDidMount
. More about authentication can be found
here
Besides that, you should also add condition inside Login
page and Register
page. To protect user from reregistering and re-logining again.
CodePudding user response:
Well probably I found a solution. Since I am setting a null value in a store as default, I've changed my PrivateRoute code to check if it is null, if it is, we wait with rendering or redirecting until it becomes true or false:
import React from 'react'
import {Route, Redirect} 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==null){
return <h2>LOADING ...</h2>
}
else if(auth.isAuthenticated==false){
return <h2>Not authenticated ... redirecting here</h2>
}
else{
return <Component {...props}/>
}
}}></Route>
)
const mapStateToProps = state =>({
auth: state.auth,
})
export default connect(mapStateToProps,null)(PrivateRoute);
Can anyone tell me if it is a good or bad idea?