From 825e4497d288aaaa7253edbe9f0196298a3407ac Mon Sep 17 00:00:00 2001 From: Javier Segarra Date: Wed, 3 Jul 2024 14:18:24 +0200 Subject: [PATCH 1/3] feat: handle request when unauthorized --- src/composables/useSession.js | 42 ++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/src/composables/useSession.js b/src/composables/useSession.js index ca2abef00..10791c9c8 100644 --- a/src/composables/useSession.js +++ b/src/composables/useSession.js @@ -58,31 +58,37 @@ export function useSession() { } } } - async function destroy() { + async function destroy(destroyTokens = true) { const tokens = { tokenMultimedia: 'Accounts/logout', token: 'VnUsers/logout', }; const storage = keepLogin() ? localStorage : sessionStorage; + let destroyTokenPromises = []; + try { + if (destroyTokens) { + const { data: isValidToken } = await axios.get('VnUsers/validateToken'); + if (isValidToken) + destroyTokenPromises = Object.entries(tokens).map(([key, url]) => + destroyToken(url, storage, key) + ); + } + } finally { + localStorage.clear(); + sessionStorage.clear(); + await Promise.allSettled(destroyTokenPromises); + const { setUser } = useState(); - for (const [key, url] of Object.entries(tokens)) { - await destroyToken(url, storage, key); + setUser({ + id: 0, + name: '', + nickname: '', + lang: '', + darkMode: null, + }); + + stopRenewer(); } - - localStorage.clear(); - sessionStorage.clear(); - - const { setUser } = useState(); - - setUser({ - id: 0, - name: '', - nickname: '', - lang: '', - darkMode: null, - }); - - stopRenewer(); } async function login(data) { From 83fa9a15b9fcc21024a6c6b0a57af23850485478 Mon Sep 17 00:00:00 2001 From: Javier Segarra Date: Wed, 3 Jul 2024 14:18:38 +0200 Subject: [PATCH 2/3] feat: redirect to login with current path --- src/boot/axios.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/boot/axios.js b/src/boot/axios.js index 4fd83ddea..fa8a08003 100644 --- a/src/boot/axios.js +++ b/src/boot/axios.js @@ -55,10 +55,10 @@ const onResponseError = (error) => { } if (session.isLoggedIn() && response?.status === 401) { - session.destroy(); + session.destroy(false); const hash = window.location.hash; const url = hash.slice(1); - Router.push({ path: url }); + Router.push(`/login?redirect=${url}`); } else if (!session.isLoggedIn()) { return Promise.reject(error); } From 57b38a87469928c68d06e756537092a23b44ae9a Mon Sep 17 00:00:00 2001 From: Javier Segarra Date: Wed, 3 Jul 2024 14:18:47 +0200 Subject: [PATCH 3/3] test: unit && e2e --- test/cypress/integration/logout.spec.js | 39 +++++++++++++++++++ .../__tests__/composables/useSession.spec.js | 1 + 2 files changed, 40 insertions(+) create mode 100644 test/cypress/integration/logout.spec.js diff --git a/test/cypress/integration/logout.spec.js b/test/cypress/integration/logout.spec.js new file mode 100644 index 000000000..b35a8415a --- /dev/null +++ b/test/cypress/integration/logout.spec.js @@ -0,0 +1,39 @@ +/// +describe('Logout', () => { + beforeEach(() => { + cy.login('developer'); + cy.visit(`/#/dashboard`); + cy.waitForElement('.q-page', 6000); + }); + describe('by user', () => { + it('should logout', () => { + cy.get( + '#user > .q-btn__content > .q-avatar > .q-avatar__content > .q-img > .q-img__container > .q-img__image' + ).click(); + cy.get('.block').click(); + }); + }); + describe('not user', () => { + beforeEach(() => { + cy.intercept('GET', '**/VnUsers/acl', { + statusCode: 401, + body: { + error: { + statusCode: 401, + name: 'Error', + message: 'Authorization Required', + code: 'AUTHORIZATION_REQUIRED', + }, + }, + statusMessage: 'AUTHORIZATION_REQUIRED', + }).as('someRoute'); + }); + it('when token not exists', () => { + cy.reload(); + cy.get('.q-notification__message').should( + 'have.text', + 'Authorization Required' + ); + }); + }); +}); diff --git a/test/vitest/__tests__/composables/useSession.spec.js b/test/vitest/__tests__/composables/useSession.spec.js index 831acbf18..789b149ec 100644 --- a/test/vitest/__tests__/composables/useSession.spec.js +++ b/test/vitest/__tests__/composables/useSession.spec.js @@ -55,6 +55,7 @@ describe('session', () => { expect(user.value).toEqual(previousUser); vi.spyOn(axios, 'post').mockResolvedValue({ data: true }); + vi.spyOn(axios, 'get').mockResolvedValue({ data: true }); await session.destroy(); user = state.getUser();