Make sure the user is logged in on any page in Angular 2

Slowly but surely progressing with Angular2. And now I am faced with the following problem. I want to check if the user is logged in or not on each page (in other words, when loading each component). Of course, I can implement the OnInit interface in each of them, but this is the smell of code.

Is there an effective way to accomplish anything that is needed on every page of the application? I would like to hear any other suggestions on best practices for solving this problem.

I use this library ( https://auth0.com/blog/2015/11/10/introducing-angular2-jwt-a-library-for-angular2-authentication/ ) for jwt based login, and I already have a good one a class of service that encapsulates all functions related to authentication. Thus, the actual verification of whether or not a user has already been performed and tested.

Thanks,

+8
angularjs angular jwt
source share
4 answers

If you use routing (and it seems to be so, as you say: “every time the page changes”) you can use several things:

  • A custom exit router (a subclass of the RouterOutlet class) is created that authenticates using the activate method. 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 information:

    • Angular 2 Authentication with Child Routes
  • Use the CanActivate decorator to verify that a component can be activated or not. In your case, you can perform authentication at this level.

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

    • Angular2. How to hide (non-visualize) a link in a menu after checking access?

This can also be handled in an HTTP interceptor (a class that extends Http ). In this case, when the request is executed, you can enable some authentication:

 @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 information:

  • How to create interceptors in Angular2?
+7
source share

I am showing you a simple implementation using Angular2. You can use the @CanActivate hook as shown in the figure to check if the user is loggedIn or not with the isLoggedIn function , which returns the promise .. p>

NOTE : the implementation below should check if the user is loggedIn before accessing any component or not. Hope some changes you can achieve what you want.

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 to the Custom Router Outlet and CanActivate Decorator , shown and implemented in this wonderful article Authentication in Angular 2

+2
source share

I think the RouterOutlet extension is a common way to achieve this.

Example posted some time ago in Gitter CaptainCodeman (not tested 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; } } 
+1
source share

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

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

Please follow below 5 minutes video tutorial

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

Note: this solution works fine for Angular 4

0
source share

All Articles