Open Closed

Cannot properly unsubscribe on logout (API calls are still invoked with error 401) #5711


User avatar
0
alexander.nikonov created

ABP 7.0.1 / Angular

My home page shows some information to an authenticated user via API calls. If the user logs out - these methods need not to be invoked anymore. Seems like I've tried all possible ways - and it still DOES call those methods with "Not authorized (401)" error from server after I click "Logout" button. I also have tried to call Subscription$.unsubscribe() while logging out, but it still does not work.

Another question: I can logout from any page, not just Home page. There are plenty of API call subscriptions on each of them. How am I supposed to unsubscribe from all such calls with minimal code changes??

Here is the piece of the code of my Home page:

        ngOnInit() {
      
          this.oAuthService.events
            .pipe(
              filter(event => event?.type === 'logout'),
              tap(() => { 
                this.logout$.next(null); //those are called, but API calls are still invoked
                this.logout$.complete();
              }))
            .subscribe();
      
          this.homeService.getNewsForHomePage()
            .pipe(filter(() => this.configStateService.getDeep('currentUser.isAuthenticated')), takeUntil(this.destroy), takeUntil(this.logout$))
            .subscribe((newsResponse) => {
              ...
            });
      
          this.homeService.getUrlsForHomePage()
            .pipe(filter(() => this.configStateService.getDeep('currentUser.isAuthenticated')), takeUntil(this.destroy), takeUntil(this.logout$))
            .subscribe((newsUrlParameterResponse) => {
              ...
            });
        }
      
        ngOnDestroy(): void {
          this.destroy.next(null);
          this.destroy.complete();    
        }

Moreover - when I am already at this page (where this.configStateService.getDeep('currentUser.isAuthenticated') is supposed to be false, I guess): the API calls are still invoked.


36 Answer(s)
  • User Avatar
    0
    masum.ulu created
    Support Team Angular Developer

    Hi again,

    If you want to unsubsribe or only subscribe when you logged in you can use isAuthenticated property in config state service for example

    Component TS

    import { Component, DestroyRef, inject } from '@angular/core';
    import { filter, finalize, map, switchMap } from 'rxjs';
    import { ConfigStateService } from '@abp/ng.core';
    import { IdentityUserService } from '@volo/abp.ng.identity/proxy';
    import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
    
    @Component({
      selector: 'app-home',
      templateUrl: './home.component.html',
      styleUrls: ['./home.component.scss'],
    })
    export class HomeComponent {
      protected readonly configStateService = inject(ConfigStateService);
      protected readonly identityUserService = inject(IdentityUserService);
    
      readonly #destryoRef = inject(DestroyRef);
    
      currentUser$ = this.configStateService.getOne$('currentUser');
      users$ = this.identityUserService.getList({ maxResultCount: 10 }).pipe(map(res => res.items));
    
      ngOnInit(): void {
        this.currentUser$
          .pipe(
            filter(currentUser => !!currentUser?.isAuthenticated),
            switchMap(() => this.identityUserService.getList({ maxResultCount: 10 })),
            map(res => res.items),
            takeUntilDestroyed(this.#destryoRef),
            finalize(() => console.log('completed'))
          )
          .subscribe(users => console.log(users));
      }
    }
    
    

    Component HTML

    <div class="card" *ngIf="(currentUser$ | async).isAuthenticated">
      <div class="card-header">{{ 'AbpIdentity::Users' | abpLocalization }}</div>
      <div class="card-body">
        <pre>{{ users$ | async | json }}</pre>
      </div>
    </div>
    

    Output

    I'm logged in

    I'm logged out

    As you can see it's not sending any request if not authenticated. In template and in TS file I create a sample that you can use.

  • User Avatar
    0
    alexander.nikonov created

    This approach works - I've already checked it before. But the problem is that I have hundreds of components, each of which has dozen of API calls. The components use base class which contains unsubscriber$ and it is used in ngOnDestroy to be nullified and complete. Thanks to that, when I go to another component, any API anywhere is properly unsubscribed (takeUntil(this.unsubscriber$)).

    Making use of one more check means I need to add this filter(...) in all those API calls. And this is not a very good approach, IMHO.... I'd prefer to make changes in the base class unsubscriber$ only - to cover logout scenario...

  • User Avatar
    0
    masum.ulu created
    Support Team Angular Developer

    This approach works - I've already checked it before. But the problem is that I have hundreds of components, each of which has dozen of API calls. The components use base class which contains unsubscriber$ and it is used in ngOnDestroy to be nullified and complete. Thanks to that, when I go to another component, any API anywhere is properly unsubscribed (takeUntil(this.unsubscriber$)).

    Making use of one more check means I need to add this filter(...) in all those API calls. And this is not a very good approach, IMHO.... I'd prefer to make changes in the base class unsubscriber$ only...

    There are 2 things here

    • Kill the stream after navigated

      • which is solved with BaseComponent strategy. But I prefer the use takeUntilDestroyed() otherwise I'll add ngOnDestroy with no meaning 🙂
    • Don't request if not authenticated; for that I've just drop a simple solution you can use similar BaseComponent strategy or much better use async pipe and handle request process on template. Create a directive for authenticated condition etc.. This case seems like a specific case

  • User Avatar
    0
    masum.ulu created
    Support Team Angular Developer

    If applying filter operator is resolves your problem, try to use interceptor and handle this filtering process at here. In that way you can decide to sending request or not in a one place. I hope these helps you

  • User Avatar
    0
    alexander.nikonov created

    Saying honestly, I still hoped I would be able to use unsubscriber$ in the component base class to control everything. It's a pity there's no some observable i can watch to change it... I would prefer not to scatter the changes around different classes (e.g. HttpInterceptor, etc.)

  • User Avatar
    0
    masum.ulu created
    Support Team Angular Developer

    🙂 unsubscriber$ will trigger when component destroy which means it won't track authenticated status. I suggest interceptor for handle authenticated status and prevent request. unsubscriber$ just kill subscription on destroy stage. Please separate the concerns

  • User Avatar
    0
    alexander.nikonov created

    I think all in all you are right about that. But there's another problem. So I put the debug point in intercept call - I'm getting there ONCE or TWO TIMES (those are request to Identity Server) after I already pressed "Logout" button: So I release the debug point and receive this bunch of API requests with error 401... I have created another ticket (https://support.abp.io/QA/Questions/5781/Logout-does-not-actually-logs-out-in-Angular-app) - that I actually cannot logout from the page other than Home page. The guy there answers he cannot do anything, because the problem is not reproduced on his end. So I don't know whether these two problems are related and what to do.

  • User Avatar
    0
    alexander.nikonov created

    Not resolved. Reopening.

  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    I think this is the same with question Can we close this and discuss in 5781?

  • User Avatar
    0
    alexander.nikonov created

    Not sure. Probably it's related. You might close this one. But if that ticket is resolved, however this problem does not go away - I will reopen this ticket.

  • User Avatar
    0
    liangshiwei created
    Support Team Fullstack Developer

    ok

Made with ❤️ on ABP v8.2.0-preview Updated on March 25, 2024, 15:11