feat(auth): enhance logout and login flow with return URL handling
This commit is contained in:
@@ -55,7 +55,7 @@ export function useClient() {
|
|||||||
return client(originalRequest);
|
return client(originalRequest);
|
||||||
} catch (refreshError) {
|
} catch (refreshError) {
|
||||||
console.error('Token refresh failed, logging out user:', refreshError);
|
console.error('Token refresh failed, logging out user:', refreshError);
|
||||||
await authStore.logout();
|
await authStore.logout('/login');
|
||||||
throw refreshError;
|
throw refreshError;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -94,6 +94,7 @@ const routes = [
|
|||||||
name: 'login',
|
name: 'login',
|
||||||
component: LoginView,
|
component: LoginView,
|
||||||
meta: { notAuthenticated: true },
|
meta: { notAuthenticated: true },
|
||||||
|
props: (route) => ({ returnUrl: route.query.returnUrl || '/landing' })
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/profile',
|
path: '/profile',
|
||||||
@@ -119,11 +120,20 @@ router.beforeEach((to, from, next) => {
|
|||||||
const authStore = useAuthStore();
|
const authStore = useAuthStore();
|
||||||
|
|
||||||
if (to.matched.some((record) => record.meta.requiresAuth)) {
|
if (to.matched.some((record) => record.meta.requiresAuth)) {
|
||||||
if (!authStore.isAuthenticated) next({ name: 'login' });
|
if (!authStore.isAuthenticated) {
|
||||||
|
next({
|
||||||
|
name: 'login',
|
||||||
|
query: { returnUrl: to.fullPath }
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
next();
|
||||||
|
}
|
||||||
} else if (to.matched.some((record) => record.meta.notAuthenticated)) {
|
} else if (to.matched.some((record) => record.meta.notAuthenticated)) {
|
||||||
if (authStore.isAuthenticated) next({ name: 'landing' });
|
if (authStore.isAuthenticated) next({ name: 'landing' });
|
||||||
|
else next();
|
||||||
|
} else {
|
||||||
|
next();
|
||||||
}
|
}
|
||||||
next();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ export const useAuthStore = defineStore(
|
|||||||
// Clear any other auth-related data if needed
|
// Clear any other auth-related data if needed
|
||||||
}
|
}
|
||||||
|
|
||||||
async function logout() {
|
async function logout(redirectTo = '/landing') {
|
||||||
try {
|
try {
|
||||||
// Optionally call logout endpoint if you have one
|
// Optionally call logout endpoint if you have one
|
||||||
// await clientApi.post('api/users/logout');
|
// await clientApi.post('api/users/logout');
|
||||||
@@ -80,7 +80,7 @@ export const useAuthStore = defineStore(
|
|||||||
console.error('Logout failed:', error);
|
console.error('Logout failed:', error);
|
||||||
} finally {
|
} finally {
|
||||||
cleanTokens();
|
cleanTokens();
|
||||||
await router.push('/');
|
await router.push(redirectTo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,8 +201,15 @@ export const useAuthStore = defineStore(
|
|||||||
// Only clear tokens and session storage after a failed refresh attempt
|
// Only clear tokens and session storage after a failed refresh attempt
|
||||||
cleanTokens();
|
cleanTokens();
|
||||||
|
|
||||||
// Force a redirect to the login page
|
// Get the current route to use as returnUrl
|
||||||
await router.push('/login');
|
const currentRoute = router.currentRoute.value;
|
||||||
|
const returnUrl = currentRoute.fullPath;
|
||||||
|
|
||||||
|
// Force a redirect to the login page with returnUrl
|
||||||
|
await router.push({
|
||||||
|
name: 'login',
|
||||||
|
query: { returnUrl }
|
||||||
|
});
|
||||||
|
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,16 +3,30 @@ import {ref} from 'vue';
|
|||||||
import {GoogleLogin} from "vue3-google-login";
|
import {GoogleLogin} from "vue3-google-login";
|
||||||
import {useAuthStore} from '@/stores/authStore.js';
|
import {useAuthStore} from '@/stores/authStore.js';
|
||||||
import {useI18n} from 'vue-i18n';
|
import {useI18n} from 'vue-i18n';
|
||||||
|
import {useRouter} from 'vue-router';
|
||||||
|
|
||||||
const {t} = useI18n();
|
const {t} = useI18n();
|
||||||
|
const router = useRouter();
|
||||||
const authStore = useAuthStore();
|
const authStore = useAuthStore();
|
||||||
|
|
||||||
const errorSnackBar = ref(false);
|
const errorSnackBar = ref(false);
|
||||||
|
const props = defineProps({
|
||||||
|
returnUrl: {
|
||||||
|
type: String,
|
||||||
|
default: '/landing'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
async function googleCallback(token) {
|
async function googleCallback(token) {
|
||||||
const response = await authStore.loginWithGoogle(JSON.stringify(token));
|
try {
|
||||||
if (response !== true) {
|
const response = await authStore.loginWithGoogle(JSON.stringify(token));
|
||||||
|
if (response === true) {
|
||||||
|
await router.push(props.returnUrl);
|
||||||
|
} else {
|
||||||
|
errorSnackBar.value = true;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Login failed:', error);
|
||||||
errorSnackBar.value = true;
|
errorSnackBar.value = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,9 +4,12 @@ import {useAuthStore} from "@/stores/authStore.js";
|
|||||||
import {useCreatorProfileStore} from "@/stores/creatorProfileStore.js";
|
import {useCreatorProfileStore} from "@/stores/creatorProfileStore.js";
|
||||||
import {useUserProfileStore} from "@/stores/userProfileStore.js";
|
import {useUserProfileStore} from "@/stores/userProfileStore.js";
|
||||||
import {useLanguageStore} from "@/stores/languageStore.js";
|
import {useLanguageStore} from "@/stores/languageStore.js";
|
||||||
|
import {useRouter, useRoute} from 'vue-router';
|
||||||
|
|
||||||
const {locale, t} = useI18n();
|
const {locale, t} = useI18n();
|
||||||
const languageStore = useLanguageStore();
|
const languageStore = useLanguageStore();
|
||||||
|
const router = useRouter();
|
||||||
|
const route = useRoute();
|
||||||
|
|
||||||
const userProfileStore = useUserProfileStore();
|
const userProfileStore = useUserProfileStore();
|
||||||
const creatorProfileStore = useCreatorProfileStore();
|
const creatorProfileStore = useCreatorProfileStore();
|
||||||
@@ -18,6 +21,14 @@ function toggleLanguage() {
|
|||||||
const nextIndex = (currentIndex + 1) % languages.length;
|
const nextIndex = (currentIndex + 1) % languages.length;
|
||||||
languageStore.setLocale(languages[nextIndex]);
|
languageStore.setLocale(languages[nextIndex]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleLogout() {
|
||||||
|
// Check if current route requires authentication
|
||||||
|
const requiresAuth = route.matched.some(record => record.meta.requiresAuth);
|
||||||
|
// If on a protected page, redirect to landing, otherwise stay on current page
|
||||||
|
const redirectTo = requiresAuth ? '/landing' : route.fullPath;
|
||||||
|
authStore.logout(redirectTo);
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -85,7 +96,7 @@ function toggleLanguage() {
|
|||||||
</template>
|
</template>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<button class="menu-item-action"
|
<button class="menu-item-action"
|
||||||
@click="authStore.logout">
|
@click="handleLogout">
|
||||||
<i class="mdi mdi-logout"></i>
|
<i class="mdi mdi-logout"></i>
|
||||||
<span class="label">{{ t('sidebar.signOut') }}</span>
|
<span class="label">{{ t('sidebar.signOut') }}</span>
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
Reference in New Issue
Block a user