Angular 2.0 SPA應(yīng)用 - 身份認證(2)

前言

一個網(wǎng)站,通常都會包含公開頁面和保護頁面兩種,如果是OA或者企業(yè)應(yīng)用網(wǎng)站,甚至可能全部都是保護頁面,訪問者需要在進行身份認證后,才能正常的瀏覽相關(guān)頁面。

路由進階應(yīng)用

在上一篇 Angular 2.0 SPA應(yīng)用 - 從腳手架開始 (1) 文章中,我們介紹了如何從一個腳手架Angular 2.0開始,添加一個首頁和登錄頁面,并實現(xiàn)了相關(guān)的路由功能。
本文中,我們將會添加一個郵件發(fā)送頁面,同時,希望只有登錄用戶可以訪問此頁面。

  1. 路由守衛(wèi)(Route Guard)
    添加AuthGuard,隨機返回True/False(分別為50%概率)。
import { Injectable } from '@angular/core';
import { Router, CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
@Injectable()
export class AuthGuard implements CanActivate {
 constructor(private router: Router) { }
 canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
     console.log('AuthGuard#canActivate called');
     if (this.checkLogin()) {
         // l已登錄,返回Ture
         console.log("AuthGuard: 用戶已登陸。");
         return true;
     }
     // 未登陸,重定向URL到登錄頁面,包含返回URL參數(shù),然后返回False
     this.router.navigate(['/login'], { queryParams: { returnUrl: state.url }});
     return false;
  }
  private checkLogin(): boolean {
     //隨機返回Ture /False
     let loggedIn:boolean = Math.random() < 0.5;
     if(!loggedIn){
         console.log("AuthGuard: 用戶未登陸。");
     }
     return loggedIn;
  }
}
  1. 郵件組件 (MailComponent)
//mail.component.ts
import {Component} from '@angular/core'
@Component({
selector: 'mail',
moduleId: __moduleName,
template: `
<div class="container" style="margin-top:100px;">
<h1>Mail Page</h1>
<div>
`
})
export class MailComponent {
}
  1. 修改app.ts
    添加MailComponent和AuthGuard引用,添加MailComponent路由并對MailComponent使用AuthGuard守護。
......
import { MailComponent } from './mail/mail.component';
import { AuthGuard } from './login/auth.guard.ts';
const appRoutes: Routes = [
  ......
  { path: 'mail', component: MailComponent, canActivate: [AuthGuard] },
 ......
];
@NgModule({
  ......
  declarations: [ App, HomeComponent, LoginComponent, MailComponent ],
  providers: [ AuthGuard ],
  ......
})

新增或修改的代碼主要功能是:

  • canActivate屬性聲明路由守衛(wèi)(Route Guard)
  • providers屬性提供依賴注入(Dependency Injection)。
  1. 修改app.template.html
    在原來的Home菜單旁邊,添加Mail菜單
<ul class="nav navbar-nav">
        <li><a routerLink="home" routerLinkActive="active">首頁</a></li>
        <li><a routerLink="mail" routerLinkActive="active">Mail</a></li>
</ul>
  • canActivate屬性聲明路由守衛(wèi)(Route Guard)
  • providers屬性聲明依賴注入(Dependency Injection)。

身份驗證

在上面的AuthGuard中,我們并沒有真正實現(xiàn)用戶身份的驗證,只是隨機返回True/False來模擬用戶已登錄或未登陸狀態(tài)下,訪問守護頁面時,路由導(dǎo)航應(yīng)有的反應(yīng)。
將驗證邏輯從AuthGuard分離,實現(xiàn)一個authenticationService,應(yīng)該包含以下功能:

  • 是否已通過身份驗證 isAuth
  • 登錄身份驗證 Login(username, password)
  • 注銷當前登錄 Logout()
  1. ** 添加 src/auth/authentication.service.ts **
 import { Injectable } from '@angular/core';

 @Injectable()
export class AuthenticationService {
isAuth() {
    if (localStorage.getItem('currentUser')) {
         return true;
     }
    else { return false; }
 }

 login(username: string, password: string) {
  if (username=='admin' && password=="admin") {
         localStorage.setItem('currentUser', username);
         return true;
      }
     else {
         return false;
     }
 }

 logout() {
     // remove user from local storage to log user out
     localStorage.removeItem('currentUser');
 }
}

好吧,我必須承認我偷懶,現(xiàn)在還是假的驗證邏輯,登陸用戶名和密碼都是"admin",就通過驗證。這樣一來,我們可以先不管復(fù)雜的后端驗證邏輯,先修改并測試前端登錄界面。

  1. ** 修改 src/login/authGuard.ts **
 import { Injectable } from '@angular/core';
 import { Router, CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
 import { AuthenticationService } from '../auth/authentication.service.ts'

 @Injectable()
export class AuthGuard implements CanActivate {
     constructor(private router: Router, private authService: AuthenticationService) { }
     canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
       console.log('AuthGuard#canActivate called');
       if (this.authService.isAuth()) {
         // l已登錄,返回Ture
         return true;
       }
       // 未登陸,重定向URL到登錄頁面,包含返回URL參數(shù),然后返回False
       this.router.navigate(['/login'], { queryParams: { returnUrl: state.url }});
       return false;
     }
}
......
  1. ** Login 組件**
    login.template.html
<div class="container">
  <div id="loginbox" style="margin-top:100px;" class="mainbox col-md-6 col-md-offset-3 col-sm-8 col-sm-offset-2">
    <div class="panel panel-info">
      <div class="panel-heading">
        <div class="panel-title">Login</div>
      </div>
      <form name="form" (ngSubmit)="f.form.valid && login()" #f="ngForm" novalidate>
        <div style="padding:30px" class="panel-body">
          <div class="form-group" [ngClass]="{ 'has-error': f.submitted && !username.valid }">
            <label for="username">Username</label>
            <input type="text" class="form-control" name="username" [(ngModel)]="model.username" #username="ngModel" required />
            <div *ngIf="f.submitted && !username.valid" class="help-block">Username is required</div>
          </div>
          <div class="form-group" [ngClass]="{ 'has-error': f.submitted && !password.valid }">
            <label for="password">Password</label>
            <input type="password" class="form-control" name="password" [(ngModel)]="model.password" #password="ngModel" required />
            <div *ngIf="f.submitted && !password.valid" class="help-block">Password is required</div>
          </div>
          <div class="form-group">
            <button [disabled]="loading" class="btn btn-primary">Login</button>
            <img *ngIf="loading" src="data:image/gif;base64,R0lGODlhEAAQAPIAAP///wAAAMLCwkJCQgAAAGJiYoKCgpKSkiH/C05FVFNDQVBFMi4wAwEAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh+QQJCgAAACwAAAAAEAAQAAADMwi63P4wyklrE2MIOggZnAdOmGYJRbExwroUmcG2LmDEwnHQLVsYOd2mBzkYDAdKa+dIAAAh+QQJCgAAACwAAAAAEAAQAAADNAi63P5OjCEgG4QMu7DmikRxQlFUYDEZIGBMRVsaqHwctXXf7WEYB4Ag1xjihkMZsiUkKhIAIfkECQoAAAAsAAAAABAAEAAAAzYIujIjK8pByJDMlFYvBoVjHA70GU7xSUJhmKtwHPAKzLO9HMaoKwJZ7Rf8AYPDDzKpZBqfvwQAIfkECQoAAAAsAAAAABAAEAAAAzMIumIlK8oyhpHsnFZfhYumCYUhDAQxRIdhHBGqRoKw0R8DYlJd8z0fMDgsGo/IpHI5TAAAIfkECQoAAAAsAAAAABAAEAAAAzIIunInK0rnZBTwGPNMgQwmdsNgXGJUlIWEuR5oWUIpz8pAEAMe6TwfwyYsGo/IpFKSAAAh+QQJCgAAACwAAAAAEAAQAAADMwi6IMKQORfjdOe82p4wGccc4CEuQradylesojEMBgsUc2G7sDX3lQGBMLAJibufbSlKAAAh+QQJCgAAACwAAAAAEAAQAAADMgi63P7wCRHZnFVdmgHu2nFwlWCI3WGc3TSWhUFGxTAUkGCbtgENBMJAEJsxgMLWzpEAACH5BAkKAAAALAAAAAAQABAAAAMyCLrc/jDKSatlQtScKdceCAjDII7HcQ4EMTCpyrCuUBjCYRgHVtqlAiB1YhiCnlsRkAAAOwAAAAAAAAAAAA=="
            />
          </div>
        </div>
      </form>
    </div>
  </div>
</div>

login.component.ts

 import { Component, OnInit } from '@angular/core';
 import { Router, ActivatedRoute } from '@angular/router';
 import { AuthenticationService } from '../auth/authentication.service';

 @Component({
  selector: 'login',
  moduleId: __moduleName,
  templateUrl: './login.template.html'
})

 export class LoginComponent {
    model: any = {};
    loading = false;
    returnUrl: string;
    constructor(private route: ActivatedRoute, private router: Router, private authService: AuthenticationService) {}

    ngOnInit() {
        // reset login status
        this.authService.logout();
        // get return url from route parameters or default to '/'
        this.returnUrl = this.route.snapshot.queryParams['returnUrl'] || '/';
    }    
    
    login() {
      this.loading = true;
      if (this.authService.login(this.model.username, this.model.password)) {
        this.router.navigate([this.returnUrl]);
      }
      else {
        this.loading = false;
      }
    }
}

由于LoginComponent.ts的構(gòu)造函數(shù)需要 AuthenticationService 依賴注入,我們需要回過頭去,修改app.ts文件,加入相關(guān)代碼,這兒就不詳細寫出來,請讀者自行摸索一下。

總結(jié)

在本文中,學(xué)習(xí)了Route Guard,加入身份認證,登錄界面做了修改,基本可以使用了,還多次使用依賴注入。如果你對這些知識點還有不清楚的地方,建議可以到 Angular 2.0 查閱文檔。
Plunker Demo

下篇預(yù)告

在兩篇文章中,基本完成了Angular SPA常用的功能介紹,貌似太快了一點點。
下篇寫啥呢,有點失去方向,身份認證繼續(xù)發(fā)展,就是引入后端服務(wù)的時候,要么介紹一下Interception和mockBackendService技術(shù),如果你有什么建議和意見,不妨告訴我,謝謝!

系列文章目錄

  1. Angular 2.0 SPA應(yīng)用 - 從腳手架開始 (1)
  2. Angular 2.0 SPA應(yīng)用 - 身份認證(2)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 前言 今天是2017年3月7日,Angular 2.0目前最新版本是 2.0.0-beta.17。網(wǎng)絡(luò)上搜索到的A...
    程序員長春閱讀 3,842評論 1 22
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,933評論 18 139
  • 第一節(jié):初識Angular-CLI第二節(jié):登錄組件的構(gòu)建第三節(jié):建立一個待辦事項應(yīng)用第四節(jié):進化!模塊化你的應(yīng)用第...
    接灰的電子產(chǎn)品閱讀 13,715評論 64 25
  • 第一節(jié):初識Angular-CLI第二節(jié):登錄組件的構(gòu)建第三節(jié):建立一個待辦事項應(yīng)用第四節(jié):進化!模塊化你的應(yīng)用第...
    接灰的電子產(chǎn)品閱讀 21,271評論 49 43
  • 【與萌共長】20171122學(xué)習(xí)力踐行Day43 今天回家繼續(xù)磨那首英文兒歌,萌已經(jīng)能完整唱出。然后萌就開始跳繩,...
    艷萍和萌寶閱讀 184評論 0 0