Hi I'm fetching a arrays of posts from my express API in the Home.vue which is protected by route guards.
<script>
export default {
created() {
this.$store.dispatch('fetchPosts')
}
}
</script>
fetchPosts action:
async fetchPosts(context) {
try {
const res = await api.get('/posts', {
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`
}
})
context.commit('SET_POSTS', res.data)
context.commit('SET_ERROR', null)
} catch(err) {
console.log(err.response.data)
context.commit('SET_ERROR', err.response.data)
}
}
In my action I commit a mutation which sets the posts object to res.data. I only want to fetchPosts when user logs in since I have a mutation which adds the post to the db and updates the posts state, when user adds a post. But because I route back to the home screen this causes the created() hook to run again, re-fetching data on each post req. App of course work fine but could be more efficient. What can I do to resolve better enhance my app?
You could check that you do not already have the state populated.
If it's empty make the API call, otherwise do nothing.
Having guards is a good thing. Depending of your app and the way you want to handle authed users, you could also wire a global middleware to your router. This will add more generic code and could be used on several places, hence less errors/duplication.
Here is an interesting article about this: https://markus.oberlehner.net/blog/implementing-a-simple-middleware-with-vue-router/
The rest of your code looks fine!
Related
In my nuxt project, i get a token from the backend that identifies the user. I tie this token to a vuex prop and save it in localstorage, so the user doesnt have to re authenticate when the page is refreshed.
To revalidate the user only when the page is actually refreshed, i wrote a beforemount function in the highest level, which is the default layout
beforeMount() {
const token = localStorage.getItem('user-token')
console.log(token)
if (token) {
this.$axios.defaults.headers.common.Authorization = token
this.$store.dispatch('auth/setToken', token)
}
}
In the next step, the router on protected pages should check if the authstate is true, which is only true if the vuex localstorage prop is set. Since i only need that on certain pages, i wrote a router middleware thats only loaded on these pages
export default function (context) {
if (!context.store.getters['auth/isAuthenticated']) {
return context.redirect('/auth?login')
}
}
Problem is, the middleware runs before the beforeMount according to the docu, which creates the problem that the middleware checks for a token which is set later and kicks the user out.
Since the only thing that comes before router middleware is global middleware, my plan was to write the reauth as global middleware. But somehow, the middleware is also called on every router change, not only before the site is created aka page refresh. This would execute the function way too often.
The goal is to set the token before the route validate based on the token, only on page refresh, since the rest is taken care of by vuex.
Trying out SvelteKit and I'm having a hard time with hooks. The docs don't really seem to explain it all too well. My current understanding of hooks is that they basically allow you to interact with requests made to your server before they get to their destination? (I'm open to a better explanation - specifically the handle hook).
My current issue is I made an endpoint called login. As the name suggests, it allows users to sign into my application by generating a token and storing it as a cookie on their client. This works until I add hooks. After reading the hooks description, I figured the handle hook is perfect for what I want to do - validate the token on each request - if invalid, reroute the user to the login screen, if valid, allow the request to continue uninterrupted.
export const handle: Handle = async ({ event, resolve }) => {
const isLogin = event.url.pathname.startsWith('/login')
const cookies = cookie.parse(event.request.headers.get('cookie') || '');
const token = cookies['token']
if (!token) {
if (!isLogin) {
return Response.redirect(`${event.url.origin}/login`)
}
return await resolve(event)
} else {
try {
await verifyToken(token)
if (isLogin) {
return Response.redirect(`${event.url.origin}/about`)
}
} catch (err) {
return Response.redirect(`${event.url.origin}/login`)
}
}
return await resolve(event)
};
This does not work as expected. When I initiate the request to the api/login endpoint, the request does not seem to make it there. I have console.logs all over the endpoint but no messages were outputted to the terminal & when I check the application storage, no new cookie was added.
What am I missing about hooks?
Why is it not passing the request off to the endpoint?
Any idea how I can fix this?
The handle hook runs for every request—including endpoints.
When you fetch /api/login without a token, your hook will redirect the request to /login since isLogin === false. You need to allow through every route that should be accessible without a login, for example:
const isLogin = /^\/(api\/)?login$/.test(event.url.pathname)
I am building a back-office app that requires users to sign in.
I have 2 external APIs:
API A : to manage user accounts and sessions
API B : to perform CRUD actions on another database (unrelated to users database)
The problem is that I don't want users to be able to perform calls to API B if their session is not valid. So I added some API endpoints in Next (under pages/api) that do the following actions:
verifying the validity of the session against API A
if session is valid: continue to step 3, if not: redirect to page /login
make the call to API B
Everything works fine if the session is valid but it fails if the session is not valid.
I have tried
res.redirect(307, '/login').end()
and
res.writeHead(307, { Location: '/login' }).end()
but it didn't work. It fails even by specifying the whole path (http://localhost:3000/login). What I don't understand is that I am successfully redirected to my /login page if I make the request directly from the browser (GET http://localhost:3000/api/data). It doesn't work when I make the request with Axios inside a React component.
Any idea how I can fix this?
As #juliomalves and #yqlim explained, I had to make the redirect manually based on the response of the API.
Faced same problem solve using below code:
Api
res.status(200).json({ success: "success" }) //add at last of the api to give response
page
import Router from 'next/router'
let res = await fetch('api', {
method: 'POST', // or 'PUT'
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
})
if (res.status == 200) {
Router.push('/location')
}
Answer is correct as #Jules Grenier sayes,but provided an example
You do not need .end(). Have you tried res.redirect(307, '/login')?
In Next.js v12 and v13, the following works for me.
// /api/example.js
const handler = async function (req, res) {
// custom logic
if (failed)
return res.redirect(307, '/login')
}
export default handler;
The API request must be initiated by a <form>.
redirect will not work with <fetch>
I have an application where a user can sign up for an event. As soon as the user has signed up, he can visit routes he couldn't before.
I'm using graphql for my api requests.
The code in my route guard looks like this:
router.beforeEach(async (to, from, next) => {
if (to.meta.signUpRequired && from.name) {
const { data: { getCurrentUser } }
= await apolloProvider.defaultClient.query({
query: USER_INFO_QUERY
});
if (getCurrentUser && getCurrentUser.isCollectionAttendee) {
return next();
}
return next('/');
}
return next();
});
This works fine and the request is not executed every time the route changes because vue-apollo caches the result. My problem is, that if the user signs up and then tries to switch the route, he can't because the cached result of the query is still used.
I don't want to use a network-only fetchPolicy before every route change.
How can I solve this?
Maybe try using this.$apolloProvider.defaultClient.resetStore() after sign-up.
I am developing an application using React js in Redux architecture
and used axios for http requests.
I have two container classes one is login and another one is home
page. In routes class i import both the container classes.
In home page container i import one action and that action imports
one axios instance variable
export var Instance_Variable = axios.create({
baseURL: URL,
headers: {
"AUTH-TOKEN": localStorage.getItem("AuthToken")
}
});
In my scenario,
the routs file will import these instance variable while importing home page class.
While login i get the auth token from the response and set it to the local storage. After logging in there was one request made in home page and respond with unauthorized(401 - The auth token validation done in application).
I am view the network tab in browser and the request made with the header "AUTH-TOKEN" : null
How do i update the instance after logging in to the application
Note: The request are works well after refreshing the application after loggin
Hello I know it’s a very old question but today I also faced this same issue and Hopefully able to solve this problem also
So, when you call the 'login API URL with Axios, if this request succeeded then you have set the header in Axios '.then' block like they said here
instance.defaults.headers.common['Authorization'] = AUTH_TOKEN;
Note: for this, you must have to use Axios interceptor
It is better to use an axios interceptor that sets header for every request like below:
axios
.interceptors
.request
.use(function (config) {
if (cookie.load('auth-token')) {
config.headers['AUTH-TOKEN'] = cookie.load('auth-token');
}
return config;
}, function (error) {
return Promise.reject(error);
});