2016-04-05 6 views
7

Lentamente ma sicuramente progredendo con Angular2. E ora ho affrontato la seguente sfida. Voglio controllare se l'utente ha effettuato il login o meno su ogni cambio di pagina (in altre parole sul carico di ogni singolo componente). Naturalmente, posso implementare l'interfaccia OnInit in ognuno di essi, ma questo è odore di codice.Controllare se l'utente ha effettuato l'accesso a qualsiasi pagina modificata in Angular 2

Esiste un modo efficace per eseguire tutto ciò che è necessario su ogni pagina dell'app? Mi piacerebbe sentire altri suggerimenti sulle migliori pratiche su come gestire questo compito.

Sto utilizzando questa libreria (https://auth0.com/blog/2015/11/10/introducing-angular2-jwt-a-library-for-angular2-authentication/) per l'accesso basato su jwt e ho già una buona classe di servizio che incapsula tutte le funzionalità relative all'autenticazione. Quindi, il controllo effettivo in cui l'utente è connesso o meno è già stato fatto e testato.

Grazie,

risposta

5

Se si utilizza il routing (e sembra essere il caso, in quanto si dice: "ad ogni cambio pagina"), è possibile sfruttare diverse cose:

  • Creare un router-outlet personalizzato (una classe secondaria di RouterOutlet) che verifica l'autenticazione con il suo metodo activate. In questo caso, puoi avere qualcosa di globale. Qualcosa del genere:

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

    Vedere questa domanda per maggiori dettagli:

  • Leverage il CanActivate decoratore da controllare è un componente può essere attivata o meno. Nel tuo caso, puoi eseguire il controllo dell'autenticazione a questo livello.

  • Si può anche fare qualcosa al livello del router per mostrare/nascondere i collegamenti del percorso. In questo caso, è possibile applicare i ruoli su questi collegamenti in base alla configurazione del percorso correlato e ai suggerimenti utente correnti. Vedere questa domanda per maggiori dettagli:

Questo può essere anche gestito all'interno di un intercettore HTTP (una classe che estende la Http uno).In questo caso, quando una richiesta è in esecuzione, è possibile collegare alcuni controlli di autenticazione:

@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(...)); 
    } 
    } 

    (...) 
} 

Vedere questa domanda per maggiori dettagli:

1

penso che si estende RouterOutlet è un modo comune per raggiungere questo

Esempio postato qualche tempo fa in Gitter da CaptainCodeman (non mi è ancora testato)

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

in realtà funziona, ma da allora il codice è stato rifattorato molto. Ecco la pagina in cui è pubblicato http://www.captaincodeman.com/2016/03/31/angular2-route-security/ –

2

sto mostrando semplice implementazione con Angular2. È possibile sfruttare il gancio @CanActivate come mostrato in figura per verificare se l'utente è connesso o meno con La funzione di accesso è che restituisce promessa.

NOTA: sotto l'implementazione è necessario verificare se l'utente è loggedIn prima di accedere a qualsiasi componente o meno. Spero che con qualche modifica tu possa ottenere ciò che vuoi avere.

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); 
}); 

Ci sono due modi per limitare l'accesso Custom Router Outlet e CanActivate Decorator mostrati e implementato in questo articolo grande Authentication in Angular 2

+0

E 'possibile reindirizzare la pagina di login dal gancio? –

+0

Non l'ho provato. Ma sarà indovinato. Ma usa il servizio di registrazione e non fa la stessa cosa. – micronyks

Problemi correlati