DEV Community

Larissa Faria Silva
Larissa Faria Silva

Posted on

Angular 19: AuthGuard CanActivate - problema com realod infinito

Definições

Guard: O que é? Como posso usa-lo?

O Guard permite o controle de rotas no Angular. Serve como checkpoints para determinar o controle de acesso a rotas específicas ou autenticação. Por exemplo, o acesso a uma rota 'home' só é possível se o usuário estiver logado antes. Para isso pode-se usar o Guard!

Criar um Guard com o Cli

ng generate guard CUSTOM_NAME

Tipos de Guard

  • CanActivate : o guard determina se o usuário pode acessar a rota. Usado para autenticação e autorização.
export const authGuard: CanActivateFn = (route: ActivatedRouteSnapshot, state: RouterStateSnapshot) => {
  const authService = inject(AuthService);
  return authService.isAuthenticated();
};
Enter fullscreen mode Exit fullscreen mode
  • CanActivateChild : o guard determina se o usuário pode acessar uma rota filha. Útil para proteger todas rotas filhas. O CanActiveChild roda para todos filhos.
export const adminChildGuard: CanActivateChildFn = (childRoute: ActivatedRouteSnapshot, state: RouterStateSnapshot) => {
  const authService = inject(AuthService);
  return authService.hasRole('admin');
};
Enter fullscreen mode Exit fullscreen mode
  • CanDeactivate : determina se o usuário pode sair de uma rota. Por exemplo, previne que usuário saia sem salvar um formulário.
export const unsavedChangesGuard: CanDeactivateFn<FormComponent> = (component: FormComponent, currentRoute: ActivatedRouteSnapshot, currentState: RouterStateSnapshot, nextState: RouterStateSnapshot) => {
  return component.hasUnsavedChanges()
    ? confirm('You have unsaved changes. Are you sure you want to leave?')
    : true;
};
Enter fullscreen mode Exit fullscreen mode

Tipos de retornos

  • boolean : se true permite a navegação, se false bloqueia

  • UrlTree ou RedirectCommand : redireciona para outra rota ao invés de bloquear

  • Promise ou Observable : a rota usa o primeiro valor emitido.

Ativando uma rota com guard

  • No documento app.routes.ts:
export const routes: Routes = [
  { path: 'home', component: HomeComponent, canActivate: [authGuard] }];
Enter fullscreen mode Exit fullscreen mode

Para mais informações acessar a página oficial.

SSR: como impacta o seu projeto?

O SSR(Server-Side Rendering) é um tipo de renderização que permite que as páginas do seu projeto carreguem mais rápido que a CSR (default do Angular). Como ele faz isso? Primeiro vamos entender o que é o CSR, e porque ele é mais lento.
O CSR (client-side rendering) carrega o conteúdo JavaScript da página antes que o usuário consiga vê-lo. Se uma página precisa buscar dados, o usuário só vai ver a página quando essa busca tiver sido concluída, o que pode fazer ter um atraso significativo no carregamento. O que também pode gerar problemas no SEO da página.

Como o SSR conserta esses problemas?

Ao invés de esperar o JS da página, o server renderiza o HTML diretamente. A latência que o usuário irá ter será apenas a da busca de dados. Também elimina a necessidade de requests adicionais, já que os dados podem ser buscados enquanto o servidor renderiza. O SSR também otimiza buscas SEO já que as search engines recebem um HTML totalmente renderizado.

Como habilitar o SSR?

Primeiro é necessário criar um projeto novo ou permitir um projeto já criado utilize o SSR.

  • Criando projeto com SSR habilitado: ng new --ssr
  • Habilitando SSR em projeto que foi criado sem SSR: ng add @angular/ssr

O SSR habilitado permite uma renderização híbrida no projeto. Certas páginas podem ter SSR, ou CSR ou pré-renderização. Todas essas podem ser escolhidas pelo desenvolvedor. É apenas necessário escolher o renderMode da página no arquivo app.routes.server.ts.
Exemplo:

// app.routes.server.ts
import { RenderMode, ServerRoute } from '@angular/ssr';
export const serverRoutes: ServerRoute[] = [
  {
    path: '', // This renders the "/" route on the client (CSR)
    renderMode: RenderMode.Client,
  },
  {
    path: 'about', // This page is static, so we prerender it (SSG)
    renderMode: RenderMode.Prerender,
  },
  {
    path: 'profile', // This page requires user-specific data, so we use SSR
    renderMode: RenderMode.Server,
  },
  {
    path: '**', // All other routes will be rendered on the server (SSR)
    renderMode: RenderMode.Server,
  },
];
Enter fullscreen mode Exit fullscreen mode

O problema do reload infinito que enfrentei

Foi a primeira vez que utilizei Guard em um projeto. Por default também acabo habilitando o SSR nos meus projetos. Estava testando para ver se com o Guard, a rota realmente estava protegida com autenticação. Primeiro testei entrar na rota autenticada. Funcionou tranquilo. Depois fui tentar sem estar autenticada, e aí encontrei um problema. A página nunca era carregada e o que deveria fazer já que não estava logada era me redirecionar para a página de login. Mas isso nunca acontecia, ficava carregando infinitamente. Depois testei recarregar a página home logada, o que gerou outra tela de carregamento infinito.
Fiquei debugando por horas, comparando com os exemplos dados pelo próprio Angular e outros tutoriais na Internet, utilizando IA que dizia que o código estava certo, mas mesmo assim a página nunca carregava. Até que encontrei no stack overflow uma pessoa com o mesmo problema e aí que resolvi. O problema ocorria porque, com SSR, as rotas eram pré-renderizadas no servidor antes de chegar ao cliente, então o guards não eram executado no server e a página ficava travada em loading. No reload, o servidor já devolvia o HTML estático e o cliente não rodava o guard rápido o suficiente para redirecionar a rota.
Dessa forma, para corrigir o problema, como a rota é protegida por guard, ativei o renderMode dela em Client, garantindo que o Guard sempre é executado antes de exibir o conteúdo. E aí o problema foi solucionado.

//app.routes.server.ts
export const serverRoutes: ServerRoute[] = [
  {path: 'home',
    renderMode: RenderMode.Client
  },
  {
    path: '**',
    renderMode: RenderMode.Prerender
  },
];
Enter fullscreen mode Exit fullscreen mode

Top comments (0)