Gerenciamento de Navegação e Autenticação em Aplicações Vue.js

O Vue Router é fundamental para gerenciar a navegação em aplicações Vue.js, oferecendo benefícios significativos.

Principais Vantagens do Vue Router:

  • Carregamento Lento de Componentes: Melhora a velocidade de carregamento inicial da página, carregando componentes apenas quando são necessários.
  • Controle de Acesso: Atua como um ponto centralizado para verificações de autenticação, prevenindo acesso não autorizado e permitindo gerenciamento granular de permissões.
  • Gerenciamento de Estado: Sincroniza o estado da aplicação com a URL, suportando nativamente as funcionalidades de avançar/retroceder do navegador e facilitando o compartilhamento de links para páginas específicas.
  • Organização do Código: Centraliza a lógica de navegação das páginas, tornando o código mais fácil de manter e expandir, além de proporcionar uma estrutura clara das relações entre as páginas.

Escopo de Atuação do Router:

O Vue Router é responsável exclusivamente pela navegação entre páginas. Ele não lida com requisições de API. O fluxo é:

Operação do Usuário → Vue Router → Renderização de Componente.

Requisições de API (via Axios/Fetch) ocorrem independentemente do roteador.

Exemplos de atuação do router:

  • /login → Exibe a página de login.
  • /article/manage → Exibe a página de gerenciamento de artigos.
  • Monitoramento e tratamento de mudanças no endereço do navegador.

Definição e Uso de Rotas:

As definições de rota especificam o mapeamento entre caminhos e componentes:


const rotas = [
   { path: '/login', component: LoginComponent },
   {
       path: '/',
       component: LayoutComponent,
       redirect: '/article/manage',
       children: [
           { path: '/article/category', component: ArticleCategory },
           { path: '/article/manage', component: ArticleManagement },
           { path: '/article/avatar', component: UserAvatar },
           { path: '/article/info', component: UserInfo },
           { path: '/article/resetPassword', component: UserPasswordReset }
       ]
   }
];
 

A navegação programática é feita através do objeto router:


const handleMenuClick = (command) => {
   if (command === 'logout') {
       authStore.clearToken();
       router.push('/login');
   } else if (command === 'profile') {
       router.push('/article/info');
   } else if (command === 'avatar') {
       router.push('/article/avatar');
   } else if (command === 'password') {
       router.push('/article/resetPassword');
   }
};
 

O fluxo real de uma requisição de API envolve:

  1. Chamada de método no componente.
  2. Função de serviço de API (ex: userService.login).
  3. Instância Axios configurada (ex: apiClient.js).
  4. Interceptors de requisição (tratamento de Token).
  5. Envio da requisição HTTP para o backend.
  6. Interceptors de resposta (tratamento do resultado).
  7. Retorno para o componente.

Mecanismo dos "Guards" de Rota:

Os "guards" de rota (como beforeEach) funcionam como verificações globais antes de cada transição de rota.


router.beforeEach((to, from, next) => {
   // Verifica se o destino é a página de login
   if (to.path === '/login') {
       next(); // Permite a navegação
       return;
   }

   // Verifica a existência do token de autenticação
   const authStore = useAuthStore(); // Assumindo um store para autenticação
   if (!authStore.isAuthenticated) {
       next('/login'); // Redireciona para o login
       return;
   }

   next(); // Permite a navegação normal
});
 

As seguintes ações disparam as verificações dos guards:

  • router.push('/article/manage')
  • router.replace('/login')
  • window.location.href = '/'

As requisições diretas via Axios ou Fetch não passam pelos guards de rota:

  • axios.get('/api/users')
  • fetch('/api/articles')

Interceptors de Requisição e Resposta:

Os interceptors do Axios permitem intervir em requisições antes de serem enviadas e nas respostas antes de serem tratadas pela aplicação.


import axios from 'axios';
import { ElMessage } from 'element-plus';
import { useAuthStore } from '@/stores/auth'; // Assumindo um store de autenticação

const API_BASE_URL = '/api';
const apiClient = axios.create({ baseURL: API_BASE_URL });

// Interceptor de Requisição
apiClient.interceptors.request.use(
   (config) => {
       const authStore = useAuthStore();
       if (authStore.token) {
           config.headers.Authorization = `Bearer ${authStore.token}`;
       }
       return config;
   },
   (error) => {
       ElMessage.error(`Erro na requisição: ${error.message}`);
       return Promise.reject(error);
   }
);

// Interceptor de Resposta
apiClient.interceptors.response.use(
   (response) => {
       // Assume que o código 0 indica sucesso
       if (response.data.code === 0) {
           return response.data;
       }
       // Trata falhas com base na mensagem do backend
       ElMessage.error(response.data.msg || 'Erro no serviço');
       return Promise.reject(response.data);
   },
   (error) => {
       ElMessage.error(error.message || 'Erro no serviço');
       return Promise.reject(error);
   }
);

export default apiClient;
 

Gerenciamento de Tokens com Pinia:

Utiliza-se o Pinia para gerenciar o estado do token de autenticação, permitindo persistência loccal.


import { defineStore } from 'pinia';
import { ref } from 'vue';

export const useAuthStore = defineStore('auth', () => {
   const token = ref('');

   const setToken = (newToken) => {
       token.value = newToken;
   };

   const clearToken = () => {
       token.value = '';
   };

   return { token, setToken, clearToken };
}, {
   // Persiste o estado no localStorage
   persist: true,
});
 

A configuração persist: true garante que o token permaneça disponível mesmo após o recarregamento da página ou o fechamento e reabertura do navegador, utilizando o localStorage por padrão.

No entanto, essa abordagem local não resolve:

  • Expiração do Token no Backend: O tempo de vida definido no servidor.
  • Riscos de Segurança: Armazenamento a longo prazo em armazenamento local.
  • Revogação Ativa: Necessidade de limpar o token em caso de logout manual.

A gestão completa da expiração de tokens requer colaboração entre frontend e backend. O frontend deve verificar periodicamente a validade do token e limpar tokens expirados. O backend deve definir tempos de expiração razoáveis e retornar códigos de status apropriados (como 401). Mecanismos como "refresh tokens" podem ser implementados para melhorar a experiência do usuário, permitindo a renovação automática do token sem intervenção.

Tags: Vue.js Vue Router Axios pinia interceptors

Publicado em 7-1 00:43