Open Closed

Public user autologin #6593


User avatar
0
vd created
  • ABP Framework version: v7.4.4
  • UI Type: Angular
  • Database System: EF Core (SQL Server)
  • Auth Server Separated (for Angular): no

I'm trying to implement public user automatic authentication (for permission management). When users access the website, I want them to be automatically connected under a single "public" user.

I tried this in app.component :

ngOnInit(): void {
        
        //...
        
        const currentUser = this.config.getOne("currentUser");

        if(currentUser == null || currentUser.id == null){
            const loginParams: LoginParams = {
                username: 'public',
                password: '**********'
            }
            this.authService.login(loginParams).subscribe(
                () => {
                    window.location.reload();
                }
            );
        }
    }

window.location.reload() is currently necessary to refresh the top right menu. If I don't reload the page, upon clicking on the user menu I get an error :

app.component.ts:38 ERROR TypeError: Cannot read properties of undefined (reading 'toggle')
    at ToolbarContainerComponent.toggleCtxMenu (volosoft-ngx-lepton-x-layouts.mjs:373:22)
    at ToolbarContainerComponent_Template_lpx_toolbar_profileClick_0_listener (volosoft-ngx-lepton-x-layouts.mjs:377:362)
    at executeListenerWithErrorHandling (core.mjs:16195:16)
    at Object.wrapListenerIn_markDirtyAndPreventDefault [as next] (core.mjs:16228:22)
    at ConsumerObserver.next (Subscriber.js:91:33)
    at SafeSubscriber._next (Subscriber.js:60:26)
    at SafeSubscriber.next (Subscriber.js:31:18)
    at Subject.js:34:30
    at errorContext (errorContext.js:19:9)
    at EventEmitter_.next (Subject.js:27:21)

How can I avoid reloading the page ?

I also tried moving the authentication code to an APP_INITIALIZER in app.module, but then, the authService is not yet initialized


11 Answer(s)
  • User Avatar
    0
    Anjali_Musmade created
    Support Team

    Hi

    Have you tried overriding Login.cshtml in backend you can write your custom logic there.

    https://docs.abp.io/pt-BR/abp/2.8/How-To/Customize-Login-Page-MVC

  • User Avatar
    0
    vd created

    Hi,

    I'm using Angular with Resource Owner Password Flow so I don't think changing Login.cshtml will help me.

    Besides, the public login should occur automatically when opening any page of the application. Not only the login page.

  • User Avatar
    0
    sinan created

    hi as a workaround, can you do something like this? With this method, you won't need to reload the page.

    export class AppComponent {
      config = inject(ConfigStateService);
      authService = inject(AuthService);
      router = inject(Router);
    
      constructor() {
        const currentUser = this.config.getOne('currentUser');
    
        if (currentUser == null || currentUser.id == null) {
          const loginParams: LoginParams = {
            username: 'admin', // change with your username
            password: '1q2w3E*', // change with your password
            redirectUrl: '/',
          };
          this.router.navigateByUrl('/account/login').then(() => {
            this.authService
              .login(loginParams)
              .subscribe();
          });
        }
      }
    }
    
  • User Avatar
    0
    vd created

    hi as a workaround, can you do something like this? With this method, you won't need to reload the page.

    export class AppComponent { 
      config = inject(ConfigStateService); 
      authService = inject(AuthService); 
      router = inject(Router); 
     
      constructor() { 
        const currentUser = this.config.getOne('currentUser'); 
     
        if (currentUser == null || currentUser.id == null) { 
          const loginParams: LoginParams = { 
            username: 'admin', // change with your username 
            password: '1q2w3E*', // change with your password 
            redirectUrl: '/', 
          }; 
          this.router.navigateByUrl('/account/login').then(() => { 
            this.authService 
              .login(loginParams) 
              .subscribe(); 
          }); 
        } 
      } 
    } 
    

    Thanks but with your workaround, the login page is displayed for 1-2 seconds before being redirected to the main page. Seeing the login page for a few seconds before it disappears is confusing for the user.

  • User Avatar
    0
    Anjali_Musmade created
    Support Team

    Hi,

    could you please check this if it helps you https://support.abp.io/QA/Questions/4484/Allow-Guest-user-to-use-certain-application-services-served-by-a-guest-page#answer-562eec34-7eec-073f-0829-3a092fd6770f

  • User Avatar
    0
    vd created

    Hi,

    could you please check this if it helps you
    https://support.abp.io/QA/Questions/4484/Allow-Guest-user-to-use-certain-application-services-served-by-a-guest-page#answer-562eec34-7eec-073f-0829-3a092fd6770f

    Right now, I'm trying to avoid refreshing the page in Angular. This link is not about Angular.

    For instance, when changing the language in any abp project, the texts are replaced without the page needing to refresh. How is it done ?

  • User Avatar
    0
    Anjali_Musmade created
    Support Team

    Hello,

    could you please check https://community.abp.io/posts/implementing-passwordless-authentication-with-asp.net-core-identity-c25l8koj

    Thanks

  • User Avatar
    0
    vd created

    The link you provided is for implementing passwordless authentication with MVC when I'm trying to figure out how to refresh the page without reloading (after autologin) in Angular.

  • User Avatar
    0
    Anjali_Musmade created
    Support Team

    Hello,

    I apologies for your inconvenience, yes that link is for MVC. Angular uses oAuth2 as an authentication method.

    To refresh the page without reloading (after autologin) in Angular try to add below code in app.comonent.ts

    export class AppComponent {
      constructor(private authService:AuthService, private router:Router)   { }
       
       ngOnInit(): void {
        
        if (this.authService.isAuthenticated) {
          this.router.navigate(this.router.getCurrentNavigation().extras.state?.redirect || ['/']);
        }
        else {
          this.router.navigate(['/']);
        }
     }
    }
    

    Thanks

  • User Avatar
    0
    vd created

    I was still getting the error so I tried another approach : replace the ToolbarComponent with my own, like explained here. In my custom toolbar, I can now check if the user is public or not and show the corresponding menu accordingly.

    However, I get another console error :

    ERROR Error: NG0100: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'null'. Current value: 'undefined'. Expression location: MyToolbarContainerComponent component. Find more at https://angular.io/errors/NG0100
        at throwErrorIfNoChangesMode (core.mjs:11010:11)
        at bindingUpdated (core.mjs:14251:17)
        at bindingUpdated2 (core.mjs:14266:12)
        at pureFunction2Internal (core.mjs:22917:12)
        at Module.ɵɵpureFunction2 (core.mjs:22711:12)
    --->    at MyToolbarContainerComponent_Template (toolbar-container.component.html:3:10)
        at ReactiveLViewConsumer.runInContext (core.mjs:11103:13)
        at executeTemplate (core.mjs:11404:22)
        at refreshView (core.mjs:12898:13)
        at detectChangesInView (core.mjs:13062:9)
    

    The problem seems to be here :

         <lpx-toolbar [profileRef]="profileRef$" (profileClick)="toggleCtxMenu()">
        <ng-container
    --->    ngIf="{
                user: userProfileService.user$ | async,
                profileRef: profileRef$ | async
            } as data"
        >
            <lpx-context-menu *ngIf="data.profileRef" #menu="lpx-context-menu" (lpxClickOutside)="menu.close()" [exceptedRefs]="[data.profileRef]">
                <lpx-context-menu-header>
                    <div class="lpx-user-ctx-header">
                        <div class="lpx-user-ctx-img">
                            <lpx-avatar [avatar]="data.user?.avatar"></lpx-avatar>
                        </div>
                        <div class="lpx-user-ctx-info">
                            <span class="lpx-context-menu-user-name">
                                {{ data.user?.fullName || data.user?.userName }}
                            </span>
                            <span *ngIf="data.user?.tenant?.name as tenantName" class="lpx-context-menu-user-tenant">
                                {{ tenantName }}
                            </span>
                            <span class="lpx-context-menu-user-email">{{ data.user?.email }}</span>
                        </div>
                    </div>
                </lpx-context-menu-header>
                <ng-container *ngFor="let actions of data.user?.userActionGroups">
                    <lpx-context-menu-action-group>
                        <lpx-navbar-routes [navbarItems]="actions" [routerItem]="false"></lpx-navbar-routes>
                    </lpx-context-menu-action-group>
                </ng-container>
            </lpx-context-menu>
        </ng-container>
    </lpx-toolbar>
    

    I downloaded lepton-x source code for comparison but there seems to be no difference between my html and yours.

  • User Avatar
    0
    Anjali_Musmade created
    Support Team

    Hello,

    Please check this discussion https://stackoverflow.com/questions/45467881/expressionchangedafterithasbeencheckederror-expression-has-changed-after-it-was

    thanks

Made with ❤️ on ABP v8.2.0 Updated on February 19, 2024, 12:29