Angular - login em dois componentes - resolvido

Hoje o sistema chama a página de login por dois componentes.

Como o componente de login é um modal.

Em cada uma dás páginas tem uma variavel logado que é boolean, para esconder ou aparecer componentes

Eu logo, mas só ajusta, quando aperto F5. Como fazer para funcionar normalmente ?

salva no localStorage, depois verifica se o user ta logado ou nao

1 curtida

Sim está em localStorage

AccountService

import { Injectable } from '@angular/core';
import { LocalStorageService, SessionStorageService } from 'ngx-webstorage';
import { ReplaySubject } from 'rxjs';
import { UsuarioLogadoModel } from '../model/usuario-logado.model';
@Injectable({ providedIn: 'root' })
export class AccountService {
  private usuarioLogado: UsuarioLogadoModel | null = null;
  private authenticationState = new ReplaySubject<UsuarioLogadoModel | null>(1);
  constructor(
    private localStorage: LocalStorageService,
    private sessionStorage: SessionStorageService
  ) {}
  authenticate(usuarioLogado: UsuarioLogadoModel | null): void {
    this.usuarioLogado = usuarioLogado;
    this.authenticationState.next(this.usuarioLogado);
  }
  isAuthenticated(): boolean {
    return (
      this.localStorage.retrieve('authentication_token') ||
      this.sessionStorage.retrieve('authentication_token')
    );
  }
}

Componente my-header.component

import { Component, OnInit } from '@angular/core';
import { MatDialog, MatDialogConfig } from '@angular/material/dialog';
import { Router } from '@angular/router';
import { AccountService } from 'src/app/core/auth/account.service';
import { AppConfirmService } from 'src/app/core/service/app-confirm/app-confirm.service';
import { LoginService } from 'src/app/core/service/login.service';
import { AlterarUsuarioLogadoComponent } from '../modal/alterar/alterar-usuario-logado.component';
import { ExtratoComponent } from '../modal/extrato/extrato.component';
import { LoginComponent } from '../modal/login/login.component';
import { NotaFiscalComponent } from '../modal/nota-fiscal/nota-fiscal.component';

@Component({
  selector: 'app-my-header',
  templateUrl: './my-header.component.html',
  styleUrls: ['./my-header.component.scss'],
})
export class MyHeaderComponent implements OnInit {
  menuState: boolean = false;
  logado: boolean;
  showNavigationIndicators = false;
  constructor(
    private confirmService: AppConfirmService,
    private loginService: LoginService,
    private dialog: MatDialog,
    private router: Router,
    private accountService: AccountService
  ) {
    this.logado = false;
  }
  async ngOnInit() {
    this.logado = await this.accountService.isAuthenticated();
  }
  meuPerfil(): void {
    const dialogConfig = new MatDialogConfig();
    dialogConfig.disableClose = true;
    dialogConfig.autoFocus = true;
    dialogConfig.width = '600px';
    this.dialog.open(AlterarUsuarioLogadoComponent, dialogConfig);
  }
  extrato(): void {
    const dialogConfig = new MatDialogConfig();
    dialogConfig.disableClose = true;
    dialogConfig.autoFocus = true;
    dialogConfig.width = '405px';
    this.dialog.open(ExtratoComponent, dialogConfig);
  }
  notaFiscal(): void {
    const dialogConfig = new MatDialogConfig();
    dialogConfig.disableClose = true;
    dialogConfig.autoFocus = true;
    dialogConfig.width = '405px';
    dialogConfig.height = '580px';
    this.dialog.open(NotaFiscalComponent, dialogConfig);
  }
  logout(): void {
    this.confirmService
      .confirm({
        title: 'Sair',
        message: 'Deseja sair do sistema ?',
      })
      .subscribe(async (res) => {
        if (!res) {
          return;
        } else {
          this.logado = false;
          this.loginService.logout();
        }
      });
  }
  showMenu(): void {
    this.menuState = !this.menuState;
  }
  getMenuState(): boolean {
    return this.menuState;
  }
  async reward() {
    this.logado = this.accountService.isAuthenticated();
    if (!this.logado) {
      this.login();
    } else {
      //this.router.navigate(['/reward']);
    }
  }
  async openeemQuiz() {
    this.logado = this.accountService.isAuthenticated();
    if (!this.logado) {
      this.login();
    } else {
      this.router.navigate(['/openeem-quiz']);
    }
  }
  async blog() {
    this.logado = this.accountService.isAuthenticated();
    this.router.navigate(['/blog']);
  }
  async sobre() {
    this.logado = this.accountService.isAuthenticated();
    //this.router.navigate(['/sobre']);
  }
  async bibliotecaCientifica() {
    this.logado = this.accountService.isAuthenticated();
    //this.router.navigate(['/biblioteca-cientifica']);
  }
  private login(): void {
    const dialogConfig = new MatDialogConfig();
    dialogConfig.disableClose = true;
    dialogConfig.autoFocus = true;
    dialogConfig.width = '393px';
    dialogConfig.height = '433px';
    const dialogRef = this.dialog.open(LoginComponent, dialogConfig);
    dialogRef.afterClosed().subscribe((retorno) => {
      if (retorno) {
        this.logado = true;
      }
    });
  }
}

Outro componente pagina-inicial-logado.component

import { Component, OnInit } from '@angular/core';
import { MatDialog, MatDialogConfig } from '@angular/material/dialog';
import { Router } from '@angular/router';
import { NgbCarouselConfig } from '@ng-bootstrap/ng-bootstrap';
import { AccountService } from 'src/app/core/auth/account.service';
import { PublicoService } from 'src/app/service/publico.service';
import { CadastrarComponent } from '../modal/cadastrar/cadastrar.component';
import { LoginComponent } from '../modal/login/login.component';
@Component({
  selector: 'app-pagina-inicial-logado',
  templateUrl: './pagina-inicial-logado.component.html',
  styleUrls: ['./pagina-inicial-logado.component.scss'],
})
export class PaginaInicialLogadoComponent implements OnInit {
  biliotecas: any[];
  logado: boolean;
  constructor(
    config: NgbCarouselConfig,
    private publicoService: PublicoService,
    private dialog: MatDialog,
    private accountService: AccountService,
    private router: Router
  ) {
    config.showNavigationIndicators = true;
    config.interval = 10000;
    this.biliotecas = [];
    this.logado = false;
  }
  async ngOnInit(): Promise<void> {
    await this.buscarUltimasTres();
    this.logado = this.accountService.isAuthenticated();
  }
  private async buscarUltimasTres(): Promise<void> {
    this.biliotecas = [];
    await this.publicoService
      .buscarUltimasTresBibliotecas()
      .then((biliotecas) => {
        biliotecas.lista.forEach((element: any) => {
          element.arquivo.url =
            'data:' +
            element.arquivo.contentType +
            ';base64,' +
            element.arquivo.arquivo;
          this.biliotecas.push(element);
        });
      });
  }
  login(): void {
    const dialogConfig = new MatDialogConfig();
    dialogConfig.disableClose = true;
    dialogConfig.autoFocus = true;
    dialogConfig.width = '393px';
    dialogConfig.height = '433px';
    const dialogRef = this.dialog.open(LoginComponent, dialogConfig);
    dialogRef.afterClosed().subscribe((retorno) => {
      if (retorno) {
        this.logado = true;
      }
    });
  }
  cadastrar(): void {
    const dialogConfig = new MatDialogConfig();
    dialogConfig.disableClose = true;
    dialogConfig.autoFocus = true;
    dialogConfig.width = '600px';
    const dialogRef = this.dialog.open(CadastrarComponent, dialogConfig);
    dialogRef.afterClosed().subscribe((retorno) => {
      if (retorno) {
        this.logado = true;
      }
    });
  }
  blog(id?: string): void {
    if (id === null || id === undefined || id === '') {
      this.router.navigate(['/blog']);
    } else {
      this.router.navigate([`blog/${id}/`]);
    }
  }
}

auth-jwt.service - aonde faz o login e guarda o token

import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { LocalStorageService, SessionStorageService } from 'ngx-webstorage';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { environment } from 'src/environments/environment';
import { CLIENTE, OAUTH, SENHA, TOKEN } from '../api/erp.api';
import { StateStorageService } from './state-storage.service';
@Injectable({ providedIn: 'root' })
export class AuthServerProvider {
  constructor(
    private http: HttpClient,
    private $localStorage: LocalStorageService,
    private $sessionStorage: SessionStorageService,
    private stateStorageService: StateStorageService
  ) {}
  getToken(): string {
    return (
      this.$localStorage.retrieve('authentication_token') ||
      this.$sessionStorage.retrieve('authentication_token') ||
      ''
    );
  }
  login(credentials: any): Observable<void> {
    let logar = '?grant_type=password';
    if (credentials.access_token && credentials.provider) {
      logar =
        logar +
        '&access_token=' +
        credentials.access_token +
        '&provider=' +
        credentials.provider;
    } else {
      logar =
        logar +
        '&username=' +
        credentials.email +
        '&password=' +
        encodeURIComponent(credentials.senha);
    }
    const headers = {
      Authorization: 'Basic ' + btoa(SENHA + ':' + CLIENTE),
    };
    return this.http
      .post<any>(environment.AUTH + OAUTH + TOKEN + logar, {}, { headers })
      .pipe(map((response: any) => this.authenticateSuccess(response, true)));
  }
  logout(): Observable<void> {
    this.stateStorageService.clearUsuarioLogado();
    return new Observable((observer) => {
      this.$localStorage.clear('authentication_token');
      this.$sessionStorage.clear('authentication_token');
      observer.complete();
    });
  }
  private authenticateSuccess(response: any, rememberMe: boolean): void {
    const jwt = response.access_token;
    if (rememberMe) {
      this.$localStorage.store('authentication_token', jwt);
    } else {
      this.$sessionStorage.store('authentication_token', jwt);
    }
  }
}

O que pode ser ?

não faço ideia kkkkkkk.


agora entendi então, se dá um reload ele funciona normal, se não der reload o funcionamento nao da certo.

Mostra o código exatamente onde acontece o problema, quando deveria dar certo e não dá

1 curtida

Pegue o hábito de usar Observable para conseguir obter uma atualização mais fácil nos seus componentes. Usando observables, vc consegue enviar notificações para os componentes que estão “escutando” determinado observable.

Dê uma lida sobre rxjs/BehaviorSubject: https://backefront.com.br/como-usar-behavior-subject/

1 curtida

Para o login funcionou

Para o logout não

private userData = new BehaviorSubject<IUser>(undefined);

    setUser(user: any): void {
        this.userData.next(user);
    }

    getUser(): Observable<any> {
        return this.userData.asObservable();
    }

Nos componentes aonde tenho que tenho que verificar se o usuário esta logado eu fiz assim:

async ngOnInit(): Promise<void> {
    await this.buscarUltimasTres();
    this.logado = false;
    this.usuarioService.getUser().subscribe((usuario) => {
      if (usuario != null) {
        this.logado = true;
      }
    });
  }

no logout fiz assim

logout(): void {
    this.usuarioService.setUser(null);
    this.authServerProvider
      .logout()
      .subscribe(null, null, () => this.accountService.authenticate(null));
    this.router.navigate(['/home']);
  }

O que errei ?

Uma pergunta, em que momento vc chama a função authenticate de AccountService?


Tente deixar o código assim:

private isAuthenticatedSubject = new BehaviorSubject<IUser>(false);

setAuthenticated(logado: boolean): void {
  this.isAuthenticatedSubject.next(logado);
}

isLogado(): Observable<boolean> {
  return this.isAuthenticatedSubject.asObservable();
}

E nos componentes, em vez de usar o boolean puro, use o observable retornado pelo isLogado. E veja se funciona. Pelo que me lembro, ao renderizar o componente, o angular entende que é um observable e já resolve ele. E caso o subject mude, o observable já será notificado na proxima vez.

1 curtida

Como falei o login funcionou.

Mas o logout não

Como está o componente que não respeitou o logout? Ele está usando o observable? São só esses dois componentes my-header.component e pagina-inicial-logado.component que devem reagir ao login e logout?

No lugar que for usar a situação de logado, vc deve usar a observable assim:

this.accountService.isLogado().subscribe(valor => this.logado = valor);
1 curtida
import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import { Observable } from 'rxjs';
import { UsuarioService } from 'src/app/service/usuario.service';
import { AccountService } from '../auth/account.service';
import { AuthServerProvider } from '../auth/auth-jwt.service';
@Injectable({ providedIn: 'root' })
export class LoginService {
  constructor(
    private authServerProvider: AuthServerProvider,
    private accountService: AccountService,
    private router: Router,
    private usuarioService: UsuarioService
  ) {}
  login(credentials: any): Observable<void> {
    return this.authServerProvider.login(credentials);
  }
  logout(): void {
    this.usuarioService.setAuthenticated(false);
    this.authServerProvider
      .logout()
      .subscribe(null, null, () => this.accountService.authenticate(null));
    this.router.navigate(['/home']);
  }
}

E os componentes onde devem aparecer/desaparecer elementos, como ele está usando a informação que o usuário está logado ou não?

1 curtida

Uma das formas de usar o observable no componente poderia ser assim:

@Component({
  selector: 'app-my-header',
  templateUrl: './my-header.component.html',
  styleUrls: ['./my-header.component.scss'],
})
export class MyHeaderComponent implements OnInit {
  // ...

  islogado: Observable<boolean>;
  
  // ...

  async ngOnInit() {
    // recupera o observable
    this.islogado = this.accountService.isAuthenticated();
  }

  // ...
}

E no template do componente:

<div *ngIf="islogado | async">
  Esse conteúdo só vai aparecer se o observable "isLogado" for true
</div>
1 curtida