Check if the user logged in on any page change in Angular 2

后端 未结 4 1080
Happy的楠姐
Happy的楠姐 2020-12-15 00:00

Slowly but surely progressing with Angular2. And now I faced the following challenge. I want to check if the user logged in or not on every page change (in other words on lo

相关标签:
4条回答
  • 2020-12-15 00:08

    I'm showing you simple implementation with Angular2. You can take advantage of @CanActivate hook as shown blow to check whether the user is loggedIn or not with isLoggedIn function which returns promise.

    NOTE: below implementation is to check whether user is loggedIn before accessing any component or not. I hope by some modification you can achieve what you want to have.

    Auth.ts

    import {Observable} from 'rxjs/Observable';
    
    export class Auth {
      constructor() {
        this.loggedIn = false;
      }
    
      login() {
        this.loggedIn = true;
      }
    
      logout() {
        this.loggedIn = false;
      }
    
      check() {
        return Observable.of(this.loggedIn);
      }
    }
    

    isLoggedIn.ts

    import {Injector} from 'angular2/core';
    import {appInjector} from './appInjector';
    import {Auth} from './Auth';
    import {Router, ComponentInstruction} from 'angular2/router';
    
    export const isLoggedIn = (next: ComponentInstruction, previous: ComponentInstruction) => {
        let injector: Injector = appInjector(); // get the stored reference to the injector
        let auth: Auth = injector.get(Auth);
        let router: Router = injector.get(Router);
    
      // return a boolean or a promise that resolves a boolean
        return new Promise((resolve) => {
          auth.check()
              .subscribe((result) => {
                        if (result) {
                            resolve(true);
                        } else {
                            router.navigate(['/Login']);
                            resolve(false);
                        }
                    });
      });
    };
    

    appInjector.ts

    import {Injector} from 'angular2/core';
    
    let appInjectorRef: Injector;
    export const appInjector = (injector?: Injector):Injector => {
        if (injector) {
          appInjectorRef = injector;
        }
    
        return appInjectorRef;
    };
    

    somecomponent.ts

    import {Component, View,ViewChild} from 'angular2/core';
    import {CanActivate} from 'angular2/router';
    import {isLoggedIn} from './isLoggedIn';
    
    @Component({
      selector: 'some',
      template: 'some text'
    })
    @CanActivate((next: ComponentInstruction, previous: ComponentInstruction) => {
      return isLoggedIn(next, previous);  // this will tell whether user is loggedIn or not. 
    })
    export class Protected {
    }
    

    boot.ts

    .
    .
    import { provide, ComponentRef } from 'angular2/core';
    import { appInjector } from './app-injector';
    .
    .
    bootstrap(AppComponent, [...]).then((appRef: ComponentRef) => {
      // store a reference to the application injector
      appInjector(appRef.injector);
    });
    

    There are two ways to restrict access Custom Router Outlet and CanActivate Decorator shown and implemented in this great article Authentication in Angular 2

    0 讨论(0)
  • 2020-12-15 00:13

    I think extending RouterOutlet is a common way to achive this

    Example posted a while ago in Gitter by CaptainCodeman (not tested myself yet)

      import {Directive, Injector, Attribute, ElementRef, DynamicComponentLoader} from 'angular2/core';
      import {Router, RouteData, RouterOutlet, RouteParams, Instruction, ComponentInstruction} from 'angular2/router';
    
      /*
        Example implementation
    
        Given a route:
        @RouteConfig([
        { path: '/thing/:id', component: ThingComponent, name: 'Thing', data: { public: false, roles:['thinger'] } }
        ])
    
        authorize(instruction: ComponentInstruction):boolean {
          // simplest case - route is public
          if (<boolean>instruction.routeData.data['public']) {
            return true;
          }
    
          // if not public then we at least need an authenticated user
          if (this.isAuthenticated()) {
            var routeRoles = <any[]>instruction.routeData.data['roles'];
            var userRoles = <string[]>this.roles();
    
            // no roles required for route = user just needs to be authenticated
            var authorized = routeRoles.length === 0 || routeRoles.some(routeRole => userRoles.indexOf(routeRole) >= 0);
    
            return authorized;
          }
    
          return false;
        }
      */
    
      export abstract class IAuthService {
        abstract isAuthenticated():boolean;
        authorize(instruction: ComponentInstruction, params:any):boolean {
          // authorized if route allows public access or user is authenticated
          return this.isAuthenticated() || <boolean>instruction.routeData.data['public']
        }
      }
    
    @Directive({selector: 'secure-outlet'})
      export class SecureRouterOutlet extends RouterOutlet {
        signin:string;
        unauthorized:string;
        injector:Injector;
    
        private parentRouter: Router;
        private authService: IAuthService;
    
        constructor(_elementRef: ElementRef, _loader: DynamicComponentLoader,
                    _parentRouter: Router, @Attribute('name') nameAttr: string,
                    authService:IAuthService,
                    injector:Injector,
                    @Attribute('signin') signinAttr: string,
                    @Attribute('unauthorized') unauthorizedAttr: string) {
          super(_elementRef, _loader, _parentRouter, nameAttr);
          this.parentRouter = _parentRouter;
          this.authService = authService;
          this.injector = injector;
          this.signin = signinAttr;
          this.unauthorized = unauthorizedAttr;
        }
    
        activate(nextInstruction: ComponentInstruction): Promise<any> {
          var params = this.getAllRouteParams(this.injector);
          var isAuthorized = this.authService.authorize(nextInstruction, params);
    
          if (isAuthorized) {
            return super.activate(nextInstruction);
          }
    
          if (this.authService.isAuthenticated()) {
            var ins = this.parentRouter.generate([this.unauthorized]);
            return super.activate(ins.component);
          } else {
            var ins = this.parentRouter.generate([this.signin,{url:location.pathname}]);
            return super.activate(ins.component);
          }
        }
    
        reuse(nextInstruction: ComponentInstruction): Promise<any> {
          return super.reuse(nextInstruction);
        }
    
        getAllRouteParams(injector) {
          let params = null;
          while(injector) {
            const routeParams = injector.getOptional(RouteParams);
            if (routeParams) {
              if (params === null) {
                params = {};
              } else {
                params = Object.create(params);
              }
    
              Object.assign(params, routeParams.params);
            }
            injector = injector.parent;
          }
          return params;
        }
      }
    
    0 讨论(0)
  • 2020-12-15 00:24

    If you use routing (and it seems to be the case since you say: "on every page change"), you can leverage several things:

    • Create a custom router-outlet (a sub class of RouterOutlet) that checks authentication with its activate method is called. In this case, you can have something global. Something like that:

      @Directive({
        selector: 'auth-outlet'
      })
      export class AuthOutlet extends RouterOutlet {
        (...)
      
        activate(oldInstruction: ComponentInstruction) {
          var url = this.parentRouter.lastNavigationAttempt;
          if (isAuthenticated()) {
            return super.activate(oldInstruction);
          } else {
            (...)
          }
        }
      }
      

      See this question for more details:

      • Angular 2 Authentication with child routes
    • Leverage the CanActivate decorator to check is a component can be activated or not. In your case, you can execute authentication checking at this level.

    • Something could also be done at the RouterLink level to show / hide route links. In this case, you can apply roles on these links based on related route configuration and current user hints. See this question for more details:

      • Angular2. How to hide(no-render) the link in the menu after check access?

    This can be also handled within an HTTP interceptor (a class that extends the Http one). In this case, when a request is executing, you can plug some authentication checks:

    @Injectable()
    export class CustomHttp extends Http {
      constructor(backend: ConnectionBackend, defaultOptions: RequestOptions) {
        super(backend, defaultOptions);
      }
    
      request(url: string | Request, options?: RequestOptionsArgs): Observable<Response> {
        console.log('request...');
        if (isAuthenticated()) {
          return super.request(url, options).catch(res => {
            // do something
          });        
        } else {
          // Redirect to login page
          // Or throw an exception: return Observable.throw(new Error(...));
        }
      }
    
      (...)
    }
    

    See this question for more details:

    • How to create interceptors in Angular2?
    0 讨论(0)
  • 2020-12-15 00:24

    This is what I did, used canActive property in app.routing.ts

     {
      path: 'dashboard',
      loadChildren: './dashboard',
      canActivate:[AuthGuard]
    }, 
    

    Please follow the below 5 minutes video tutorial

    https://www.youtube.com/watch?v=0Qsg8fyKwO4

    Note: This solution works fine for Angular 4

    0 讨论(0)
提交回复
热议问题