I got an unexpected behavior when a user login to app. I store a jwt token in a cookie. Before logging into app,I checked whether jwt token is exists and that token is valid with backend.
Below is my code. Here is app.js.
class App extends Component {
render() {
return (
<BrowserRouter>
<Layout>
<LoginRoute></LoginRoute>
</Layout>
</BrowserRouter>
);
}
}
LoginRoute component is as below.
const LoginRoute = withRouter(({ history }) => (
isValidUser() ? (
<Switch>
<Route path="/incident-reporting" component={Home}></Route>
<Redirect path='/' to='/incident-reporting/home' />
<NotFound />
</Switch>
) : (
<Switch>
<Route path="/" exact component={Login}></Route>
<NotFound></NotFound>
</Switch>
)
))
Here is isValidUser()
const isValidUser = () => {
if (cookies.get("token")) {
let token = cookies.get("token")
axios.get("https://0.0.0.0:9094/auth/v1.0.0/user-info", {
headers: { 'Authorization': 'Bearer ' + token }
}).then(
response => {
return true;
}
).catch(
error => {
return false;
}
)
//return true
} else {
return false;
}
}
But I can't login in to app with valid token. isValidUser() return undefined before exucuting axios post request. How to solve this problem?
Your function should be asynchronous, either with ES6 async, returning promises or using callbacks. Otherwise calling the axios.get function just "falls through" and it returns the default undefined value.
You need to wait for the isValidUser to finish. To do that, you can do this:
const LoginRoute = withRouter(async ({ history }) => (
let isUserValid = await isValidUser()
isUserValid ? (
<Switch>
<Route path="/incident-reporting" component={Home}></Route>
<Redirect path='/' to='/incident-reporting/home' />
<NotFound />
</Switch>
) : (
<Switch>
<Route path="/" exact component={Login}></Route>
<NotFound></NotFound>
</Switch>
)
))
And on the isValidUser:
const isValidUser = () => {
if (cookies.get("token")) {
let token = cookies.get("token")
return axios.get("https://0.0.0.0:9094/auth/v1.0.0/user-info", {
headers: { 'Authorization': 'Bearer ' + token }
}).then(
response => {
return true;
}
).catch(
error => {
return false;
}
)
//return true
} else {
return false;
}
}
Related
I have an App component that checks if I have a token and then loads the components for authorized ones, if not then only the login page is available.
const App: FC<any> = () => {
const { token } = useToken();
if (token && Object.values(user)) {
return <LoggedInComponent />;
}
return <LoggedOutComponent />;
};
const LoggedInComponent: FC<any> = () => {
return (
<BrowserRouter>
<Switch>
<Route path="/" exact={true} component={ForLoggedInUsers} />
<Redirect from={'*'} to={'/'} />
</Switch>
</BrowserRouter>
);
};
const LoggedOutComponent: FC<any> = () => {
return (
<BrowserRouter>
<Switch>
<Route path="/" exact={true} component={Login} />
<Redirect from={'*'} to={'/'} />
</Switch>
</BrowserRouter>
);
};
Token hook just writes the received token to session storage.
export default function useToken() {
const getToken = (): string => {
const tokenString: string | null = sessionStorage.getItem('X-JWT');
let userToken;
if (tokenString) {
userToken = JSON.parse(tokenString);
}
return userToken;
};
const [token, setToken] = useState(getToken());
const saveToken = (userToken: string): void => {
sessionStorage.setItem('X-JWT', JSON.stringify(userToken));
setToken(userToken);
};
return {
setToken: saveToken,
token
};
}
The problem is that if I write a non-valid token in sessionstorage ('X-JWT': 'not-valid') then I'm still redirected to the page as authorized. What should I do to recognize a valid token in session storage?
I want to direct User Profile when a username is clicked. When click the username, get the data of users data is taken and define to userProfile with setUserProfile. After that, get the data of user posts. Then direct to the /users/${userName}. Everything works correctly until coming to the Map function inside UserPost.js but the inside of the userPosts.map() function is not rendered.
After Click the username the API calls start using the username:
useEffect(() => {
async function fetchProfileAPI() {
if (userName == undefined) {
return null;
}
const urlUserbyName = `http://localhost:5000/users/${userName}`;
const result = await axios(urlUserbyName);
setUserProfile(result.data);
}
fetchProfileAPI();
}, [userName]);
useEffect( () => {
async function fetchUserPostsAPI() {
if (userProfile == undefined) {
return null;
}
const postsOfUser = userProfile.createdPost;
const postArray = [];
postsOfUser.map(async (postId) => {
const urlPostbyId = `http://localhost:5000/posts/${postId}`;
const result = await axios(urlPostbyId);
postArray.push(result.data);
})
console.log(postArray);
setUserPosts(postArray);
}
fetchUserPostsAPI();
},[userProfile]);
// History.Push in useEffect
useEffect(() => {
if(userProfile == undefined) {
console.log("Nullmuş ya la");
return null;
}
console.log("Null değilmiş ya la");
history.push(`/users/${userProfile.username}`);
},[userPosts]);
App.js React Router Part
const App = () => {
const { postId, userName } = useContext(MemoryContext);
return (
<>
<Router>
<Switch>
<Route path={`/users/${userName}`} exact>
<Header/>
<Profile/>
<UserPosts/>
</Route>
<Route path={`/posts/${postId}`} exact>
<Header />
<SinglePost/>
</Route>
<Route path="/posts" exact>
<Header />
<PostsList />
<AddPost />
</Route>
<Route path="/" exact>
<Header />
<PostsList />
<AddPost />
</Route>
</Switch>
</Router>
</>
)
}
UserPost.js
Everything is fine until here.
const UserPost = () => {
const { userPosts } = useContext(MemoryContext);
console.log(userPosts); // This line is printed to console and shows the api call is working correctly
return (
<Container>
<Row>
{console.log("UserPosts Rendered...")} {/*This line is printed to console*/}
{userPosts.map((post, key) => {
return (
<Col key={key} xs={10} md={6} lg={4} className="offset-1 offset-md-0 py-5 px-3">
{console.log("UsersPost.map working") /*This line is not printed to console*/}
</Col>
)
})}
</Row>
</Container>
)
}
i have a problem here with my protected routes in react.js so
i go get the token item in the sessionStorage after that i validade if the token is valid if not returns null
so when i did my protected routes it protects the routes but when i have a valid token in Session Storage if i refresh the page redirects me to the login
MOUNTCOMPONENT
state = {};
componentDidMount() {
try {
const jwt = sessionStorage.getItem('Token');
const user = jwtDecode(jwt);
console.log(user);
this.setState({ user });
} catch (e) {
return null;
}
}
Routes
render() {
const { user } = this.state;
return (
<div className='form'>
<BrowserRouter>
<Switch>
<Route exact path='/registo' component={registo} />
<Route path='/login' component={Login} />
<Route
path='/dashboardVet'
render={(props) => {
if (!user) return <Redirect to='/login' />;
return <Dashboard {...props} />;
}}
/>
I have a React Native app with an authentication process. To get the Authentication, I use Async Storage to store the token and retrieve the token.
I created a method to get the token from the Async storage, but the problem is, I can't use the token in other functions by assigning it to another variable. The function call of the method I created always returns a Promise instead of the token.
App.js
const getToken = async () => {
var value = "";
try {
await AsyncStorage.getItem('accessToken').then(val => {
value = val;
})
} catch (e) {
console.log("error getting token", e)
}
console.log("token", value) // here I can see the correct token
return value;
}
const AuthRoute = ({ component: Component, ...rest }) => (
<Route {...rest} render={props => {
if (Auth.isAuthenticated()) {
var idToken = getToken().then(t => { return t });
console.log("token", idToken) // here it is a Promise
if (idToken) {
return <Component {...props} />
}
return <Redirect to={{ pathname: `/signup` }} />
}
else {
// return <Component {...props} />
return <Redirect to={{ pathname: `/signup` }} />
}
}} />
)
How can I solve this?
Once you have a Promise, all the code depending on the promise will need to be chain using Promise.then(functionThatDoesMoreThings) or you will need to await Promise... and then do things.
Most people prefer async/await... so in your case it will look like:
const AuthRoute = ({ component: Component, ...rest }) => (
<Route {...rest} render={async props => {
if (Auth.isAuthenticated()) {
var idToken = await getToken();
console.log("token", idToken) // it should print the token
if (idToken) {
return <Component {...props} />
}
return <Redirect to={{ pathname: `/signup` }} />
}
else {
// return <Component {...props} />
return <Redirect to={{ pathname: `/signup` }} />
}
}} />
i am developping a Reactjs-nodejs application. I would like to make a JWT authentification. when we log in, i give a unique token to the user. Then, thanks to this token, if it is valid, i allow the user to navigate through my router. my private route component is like :
PrivateRoute
My function getId is like that:
async function getId(){
let res = await axios('_/api/users/me',{config}).catch(err => { console.log(err)});
return res+1;
}
Finally the config component is the token stored in the localStorage :
const config = {
headers: { Authorization: ${window.localStorage.getItem("token")} }
};
GetId() returns the id of the user if logged in, else it is null.
The problem now is that my privateRoute always redirect to "/" path. I think it is because of the axios(promise) that gives me the userId too late. please tell me if you understand well and if you have a solution.
Thanks you
You can create private-route like this .
const PrivateRoute = ({ component: Component, ...props }) => {
return (
<Route
{...props}
render={innerProps =>
localStorage.getItem("Token") ? (
<Component {...innerProps} />
) : (
<Redirect
to={{
pathname: "/",
state: { from: props.location }
}}
/>
)
}
/>
);
};
then you can use
<PrivateRoute path="/" component={FIlname} />
if you are using redux, you can make the following:
in reduer:
case LOGIN_ADMIN_SUCCESS:
localStorage.setItem("token", action.payload.token);
return {
...state,
user: action.payload,
isSignedIn: true,
loadingSignIn: false,
token: action.payload.token,
};
then in your private router you have to check these values, like
const PrivateRoute = ({ component: Component, admin, ...rest }) => (
<Route
{...rest}
render={(props) => {
if (admin.loadingSignIn) {
return <h3>Loading...</h3>;
} else if (!admin.isSignedIn) {
return <Redirect to="/login" />;
} else {
return <Component {...props} />;
}
}}
/>
);