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

前言

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

路由進(jìn)階應(yīng)用

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

  1. 路由守衛(wèi)(Route Guard)
    添加AuthGuard再姑,隨機(jī)返回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到登錄頁(yè)面,包含返回URL參數(shù)栖疑,然后返回False
     this.router.navigate(['/login'], { queryParams: { returnUrl: state.url }});
     return false;
  }
  private checkLogin(): boolean {
     //隨機(jī)返回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路由并對(duì)MailComponent使用AuthGuard守護(hù)蔽挠。
......
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
    在原來(lái)的Home菜單旁邊,添加Mail菜單
<ul class="nav navbar-nav">
        <li><a routerLink="home" routerLinkActive="active">首頁(yè)</a></li>
        <li><a routerLink="mail" routerLinkActive="active">Mail</a></li>
</ul>
  • canActivate屬性聲明路由守衛(wèi)(Route Guard)
  • providers屬性聲明依賴注入(Dependency Injection)澳淑。

身份驗(yàn)證

在上面的AuthGuard中比原,我們并沒(méi)有真正實(shí)現(xiàn)用戶身份的驗(yàn)證,只是隨機(jī)返回True/False來(lái)模擬用戶已登錄或未登陸狀態(tài)下杠巡,訪問(wèn)守護(hù)頁(yè)面時(shí)量窘,路由導(dǎo)航應(yīng)有的反應(yīng)。
將驗(yàn)證邏輯從AuthGuard分離氢拥,實(shí)現(xiàn)一個(gè)authenticationService蚌铜,應(yīng)該包含以下功能:

  • 是否已通過(guò)身份驗(yàn)證 isAuth
  • 登錄身份驗(yàn)證 Login(username, password)
  • 注銷當(dāng)前登錄 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');
 }
}

好吧,我必須承認(rèn)我偷懶嫩海,現(xiàn)在還是假的驗(yàn)證邏輯冬殃,登陸用戶名和密碼都是"admin",就通過(guò)驗(yàn)證叁怪。這樣一來(lái)审葬,我們可以先不管復(fù)雜的后端驗(yàn)證邏輯,先修改并測(cè)試前端登錄界面奕谭。

  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到登錄頁(yè)面血柳,包含返回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 依賴注入,我們需要回過(guò)頭去难捌,修改app.ts文件膝宁,加入相關(guān)代碼,這兒就不詳細(xì)寫出來(lái)根吁,請(qǐng)讀者自行摸索一下昆汹。

總結(jié)

在本文中,學(xué)習(xí)了Route Guard婴栽,加入身份認(rèn)證满粗,登錄界面做了修改,基本可以使用了愚争,還多次使用依賴注入映皆。如果你對(duì)這些知識(shí)點(diǎn)還有不清楚的地方挤聘,建議可以到 Angular 2.0 查閱文檔。
Plunker Demo

下篇預(yù)告

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

系列文章目錄

  1. Angular 2.0 SPA應(yīng)用 - 從腳手架開始 (1)
  2. Angular 2.0 SPA應(yīng)用 - 身份認(rèn)證(2)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市缝其,隨后出現(xiàn)的幾起案子挎塌,更是在濱河造成了極大的恐慌,老刑警劉巖内边,帶你破解...
    沈念sama閱讀 219,366評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件榴都,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡漠其,警方通過(guò)查閱死者的電腦和手機(jī)嘴高,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)辉懒,“玉大人阳惹,你說(shuō)我怎么就攤上這事谍失】袅” “怎么了?”我有些...
    開封第一講書人閱讀 165,689評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵快鱼,是天一觀的道長(zhǎng)颠印。 經(jīng)常有香客問(wèn)我,道長(zhǎng)抹竹,這世上最難降的妖魔是什么线罕? 我笑而不...
    開封第一講書人閱讀 58,925評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮窃判,結(jié)果婚禮上钞楼,老公的妹妹穿的比我還像新娘。我一直安慰自己袄琳,他們只是感情好询件,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,942評(píng)論 6 392
  • 文/花漫 我一把揭開白布燃乍。 她就那樣靜靜地躺著,像睡著了一般宛琅。 火紅的嫁衣襯著肌膚如雪刻蟹。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,727評(píng)論 1 305
  • 那天嘿辟,我揣著相機(jī)與錄音舆瘪,去河邊找鬼。 笑死红伦,一個(gè)胖子當(dāng)著我的面吹牛英古,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播色建,決...
    沈念sama閱讀 40,447評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼哺呜,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了箕戳?” 一聲冷哼從身側(cè)響起某残,我...
    開封第一講書人閱讀 39,349評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎陵吸,沒(méi)想到半個(gè)月后玻墅,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,820評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡壮虫,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,990評(píng)論 3 337
  • 正文 我和宋清朗相戀三年澳厢,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片囚似。...
    茶點(diǎn)故事閱讀 40,127評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡剩拢,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出饶唤,到底是詐尸還是另有隱情徐伐,我是刑警寧澤,帶...
    沈念sama閱讀 35,812評(píng)論 5 346
  • 正文 年R本政府宣布募狂,位于F島的核電站办素,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏祸穷。R本人自食惡果不足惜性穿,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,471評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望雷滚。 院中可真熱鬧需曾,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,017評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至桑嘶,卻和暖如春炊汹,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背逃顶。 一陣腳步聲響...
    開封第一講書人閱讀 33,142評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工讨便, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人以政。 一個(gè)月前我還...
    沈念sama閱讀 48,388評(píng)論 3 373
  • 正文 我出身青樓霸褒,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親盈蛮。 傳聞我的和親對(duì)象是個(gè)殘疾皇子废菱,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,066評(píng)論 2 355

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

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