Angular CanActivate
限制Route.path
存取Component的範例。
範例環境:
- Windows 64 Bit
- Angular CLI: 7.3.9
- Angular: 7.2.16
請先參考「Angular 使用Session Storage登入登出簡單範例」,本篇將以該篇進行修改。
在「Angular 使用Session Storage登入登出簡單範例」只使用了單一個LoginComponent
演示登入登出的效果;本篇則拆開為登入前LoginComponent
與登入後HelloComponent
。
新增一個Service名為AuthService
並實作CanActivate
介面的canActivate()
來決定/hello
是否可被存取,返回true
代表可存取,false
代表不可存取。
此外把原本LoginComponent
的登入登出邏輯搬到這裡。
AuthService (auth.service.ts)
import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
@Injectable({
providedIn: 'root'
})
export class AuthService implements CanActivate { // <--實作CanActivate
constructor() { }
/** 實作CanActivate.canActivate() */
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
const user = sessionStorage.getItem('user');
if (user === null) {
return false;
} else {
return true;
}
}
/** 驗證使用者身分 */
authentcate(username: string, password: string) {
if (username === 'matt' && password === '123') {
sessionStorage.setItem('user', username);
return true;
} else {
return false;
}
}
/** 清除session storage的使用者名稱 */
clearSession() {
sessionStorage.removeItem('user');
}
}
修改LoginComponent
如下。login()
驗證的邏輯委託給AuthService.authentcate()
。
LoginComponent (login.component.ts)
import { Component, OnInit } from '@angular/core';
import { AuthService } from '../service/auth.service';
import { Router } from '@angular/router';
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
username: string;
password: string;
isFail: boolean = false;
warnMessage: string = '帳號或密碼錯誤';
constructor(
private authService: AuthService,
private router: Router
) {
}
ngOnInit() {
}
login() {
if (this.authService.authentcate(this.username, this.password)) {
this.isFail = false;
this.router.navigate(['hello']); // 登入後導向 /hello 頁面
} else {
this.isFail = true;
}
}
}
修改login.component.html
如下。
login.component.html
<div>
<div style="color:red;" *ngIf='isFail'>{{warnMessage}}</div>
<div>
<label>帳號:<input type="text" name="username" [(ngModel)]="username"></label><br>
<label>密碼:<input type="password" name="password" [(ngModel)]="password"></label><br>
<button (click)=login()>Login</button>
</div>
</div>
新增一個Component名為HelloComponent
做為登入後的頁面。
修改HelloComponent
如下。
HelloComponent (hello.component.ts)
import { Component, OnInit } from '@angular/core';
import { AuthService } from '../service/auth.service';
import { Router } from '@angular/router';
@Component({
selector: 'app-hello',
templateUrl: './hello.component.html',
styleUrls: ['./hello.component.css']
})
export class HelloComponent implements OnInit {
username: string;
constructor(
private authService: AuthService,
private router: Router
) {
this.username = sessionStorage.getItem('user'); // HelloComponent初始時從session storage取得登入者名稱
}
ngOnInit() {
}
logout() {
this.authService.clearSession(); // 清除session storage的使用者名稱
this.router.navigate(['login']); // 登出後導向 /login 頁面
}
}
修改hello.component.html
如下。
hello.component.html
<div>
<h1>Hello {{username}}</h1>
<button (click)=logout()>Log out</button>
</div>
開啟AppRoutingModule
(app-routing.module.ts
),設定HelloComponent
的Route.path
為'hello'
。
AppRoutingModule (app-routing.module.ts)
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { LoginComponent } from './login/login.component';
import { HelloComponent } from './hello/hello.component';
import { AuthService } from './service/auth.service';
const routes: Routes = [
{path:'login', component:LoginComponent},
{path:'hello', component:HelloComponent} // 設定/hello為導向HelloComponent的路徑
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
完成以上後啟動專案,登入登出的效果如下。可以發現就算沒有登入也是能直接在瀏覽器網址輸入/hello
導向原本要登入才能存取的HelloComponent
。
為了解決以上問題,可以利用Route.canActivate
設定CanActivate
的實作,也就是上面的AuthService.canActivate()
來決定/hello
是否能被存取。
在AppRoutingModule
設定/hello
的canActivate
為AuthService
如下。
AppRoutingModule (app-routing.module.ts)
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { LoginComponent } from './login/login.component';
import { HelloComponent } from './hello/hello.component';
import { AuthService } from './service/auth.service';
const routes: Routes = [
{path:'login', component:LoginComponent},
{path:'hello', component:HelloComponent, canActivate: [AuthService]} // 設定/hello需經AuthService.canActivate()判斷是否可存取
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
設定canActivate
後若未登入而直接在瀏覽器輸入/hello
則返回空白結果。
或是改成導回登入頁面。修改AuthService
如下。
AuthService (auth.service.ts)
import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router';
@Injectable({
providedIn: 'root'
})
export class AuthService implements CanActivate {
constructor(private router: Router) { } // 注入Router
/** 實作CanActivate.canActivate() */
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
const user = sessionStorage.getItem('user');
if (user === null) {
this.router.navigate(['login']); // 改為導向 /login
} else {
return true;
}
}
/** 驗證使用者身分 */
authentcate(username: string, password: string) {
if (username === 'matt' && password === '123') {
sessionStorage.setItem('user', username);
return true;
} else {
return false;
}
}
/** 清除session storage的使用者名稱 */
clearSession() {
sessionStorage.removeItem('user');
}
}
修改後未登入直接在瀏覽器網址輸入/hello
則導回/login
登入頁面。
範例專案src/app
目錄結構如下。
../src/app
│
│ app-routing.module.ts
│ app.component.css
│ app.component.html
│ app.component.spec.ts
│ app.component.ts
│ app.module.ts
│
├─hello
│ hello.component.css
│ hello.component.html
│ hello.component.spec.ts
│ hello.component.ts
│
├─login
│ login.component.css
│ login.component.html
│ login.component.spec.ts
│ login.component.ts
│
└─service
auth.service.spec.ts
auth.service.ts
參考:
沒有留言:
張貼留言