2016-04-05 27 views
7

用Angular2緩慢但肯定地進步。現在我面臨以下挑戰。我想檢查用戶是否登錄或者沒有更改每個頁面(換言之,每個組件的負載)。當然,我可以在其中的每一個實現OnInit接口,但這是代碼味道。檢查用戶是否在Angular 2中的任何頁面上更改

是否有任何有效的方式來執行應用程序的每個頁面上需要的任何東西?我很想聽聽關於如何處理此任務的最佳做法的其他建議。

我使用這個庫(https://auth0.com/blog/2015/11/10/introducing-angular2-jwt-a-library-for-angular2-authentication/)爲基於jwt的登錄,我已經有一個很好的服務類,封裝所有認證相關的功能。因此,實際檢查用戶是否登錄已經完成並經過測試。

感謝,

回答

5

如果使用路由(這似乎是因爲你說的情況:「在每一頁上的變化」),您可以利用幾件事情:

  • 創建一個自定義的路由器出口(子類RouterOutlet),它調用其activate方法檢查驗證。在這種情況下,你可以擁有全局的東西。類似的東西:

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

    看到這個問題的更多細節:

  • 槓桿CanActivate裝飾檢查是一個組件可以被激活。在你的情況下,你可以在這個級別執行驗證檢查。

  • 也可以在RouterLink級別上進行顯示/隱藏路由鏈接。在這種情況下,您可以根據相關路由配置和當前用戶提示在這些鏈接上應用角色。看到這個問題更多細節:

這可以一個HTTP攔截器(即延伸Http一個類)內也處理。在這種情況下,當一個請求正在執行,你可以插入一些認證檢查:

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

    (...) 
} 

詳情請參見這個問題:

1

我想延長RouterOutlet是實現這一目標

實例發佈前一陣子在的Gitter由CaptainCodeman的常用方法(未測試自己還)

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

它的實際工作中實現,但自那時以來,代碼已經被重構了很多。這裏是發佈的頁面http://www.captaincodeman.com/2016/03/31/angular2-route-security/ –

2

我展示你簡單用Angular2實現。您可以利用@CanActivate掛鉤如圖所示查看用戶是否登錄或不在isLoggedIn功能其中返回承諾

備註:下面的實現是在訪問任何組件之前檢查用戶是否爲loggedIn。我希望通過一些修改你可以達到你想要的。

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

有兩種方法來限制訪問Custom Router OutletCanActivate Decorator顯示和這篇大文章Authentication in Angular 2

+0

是否有可能從鉤子重定向到登錄頁面? –

+0

我還沒有測試過。但這將是我猜。但它使用loggIn服務,它沒有同樣的事情。 – micronyks

相關問題