Angular 2.0 SPA应用 - 身份认证(2)

前言

一个网站,通常都会包含公开页面和保护页面两种,如果是OA或者企业应用网站,甚至可能全部都是保护页面,访问者需要在进行身份认证后,才能正常的浏览相关页面。

路由进阶应用

在上一篇 Angular 2.0 SPA应用 - 从脚手架开始 (1) 文章中,我们介绍了如何从一个脚手架Angular 2.0开始,添加一个首页和登录页面,并实现了相关的路由功能。
本文中,我们将会添加一个邮件发送页面,同时,希望只有登录用户可以访问此页面。

  1. 路由守卫(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参数,然后返回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: `

Mail Page

` }) 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属性声明路由守卫(Route Guard)
  • providers属性提供依赖注入(Dependency Injection)。
  1. 修改app.template.html
    在原来的Home菜单旁边,添加Mail菜单

  • canActivate属性声明路由守卫(Route Guard)
  • providers属性声明依赖注入(Dependency Injection)。

身份验证

在上面的AuthGuard中,我们并没有真正实现用户身份的验证,只是随机返回True/False来模拟用户已登录或未登陆状态下,访问守护页面时,路由导航应有的反应。
将验证逻辑从AuthGuard分离,实现一个authenticationService,应该包含以下功能:

  • 是否已通过身份验证 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');
 }
}

好吧,我必须承认我偷懒,现在还是假的验证逻辑,登陆用户名和密码都是"admin",就通过验证。这样一来,我们可以先不管复杂的后端验证逻辑,先修改并测试前端登录界面。

  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参数,然后返回False
       this.router.navigate(['/login'], { queryParams: { returnUrl: state.url }});
       return false;
     }
}
......
  1. ** Login 组件**
    login.template.html
Login
Username is required
Password is required

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的构造函数需要 AuthenticationService 依赖注入,我们需要回过头去,修改app.ts文件,加入相关代码,这儿就不详细写出来,请读者自行摸索一下。

总结

在本文中,学习了Route Guard,加入身份认证,登录界面做了修改,基本可以使用了,还多次使用依赖注入。如果你对这些知识点还有不清楚的地方,建议可以到 Angular 2.0 查阅文档。
Plunker Demo

下篇预告

在两篇文章中,基本完成了Angular SPA常用的功能介绍,貌似太快了一点点。
下篇写啥呢,有点失去方向,身份认证继续发展,就是引入后端服务的时候,要么介绍一下Interception和mockBackendService技术,如果你有什么建议和意见,不妨告诉我,谢谢!

系列文章目录

  1. Angular 2.0 SPA应用 - 从脚手架开始 (1)
  2. Angular 2.0 SPA应用 - 身份认证(2)

你可能感兴趣的:(Angular 2.0 SPA应用 - 身份认证(2))