Guarding routes
這個主要是拿來防禦(X)某個 path 被 activate
那就來設定一個防止未登入使用者任意存取 view 的 Guard:
先來建立一個新的 guard
ng g s services/auth-guard
接著要實作 Guard 的內容了
import { Injectable } from '@angular/core';
import { CanActivate, Router, ActivatedRouteSnapshot, RouterStateSnapshot} from '@angular/router';
import { UserService } from './user.service';
@Injectable()
export class AuthGuardService implements CanActivate {
constructor(
private userService: UserService,
private router: Router
) { }
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
if (!this.userService.isGuest()){
return true;
}
else {
this.router.navigate(['/login'], {
queryParams: {
return: state.url
}
});
return false
}
}
}
Guard 定義好了要怎麼掛?答案是要設定在 route 的規則如下:
const appRoutes: Routes = [
{ path: 'login', component: LoginComponent },
{ path: 'users', component: ChatListComponent, outlet: 'chat', canActivate: [AuthGuardService]},
{ path: 'users/:username', component: ChatComponent, outlet: 'chat', canActivate: [AuthGuardService]},,
{ path: 'blogs', loadChildren: 'app/blogs/blogs.module#BlogsModule' },
{ path: '', redirectTo: '/forums', pathMatch: 'full'},
{ path: '**', component: NotFoundComponent }
];
來試看看是不是能守備成功 
登入完成之後,要把使用者導回原本的 view
首先,要調整 LoginComponent 的 controller 如下:
import { Component, OnInit } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router';
import { UserService } from '../services/user.service';
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
username: string = '';
password: string = '';
return: string = '';
constructor(
private userService: UserService,
private router: Router,
private route: ActivatedRoute
) { }
ngOnInit() {
this.route.queryParams.subscribe((params) => {
this.return = params['return'] || '/forums';
if (!this.userService.isGuest()) {
this.go();
}
});
}
login() {
if (this.username && this.password) {
this.userService.login(this.username);
this.go();
}
}
go() {
this.router.navigateByUrl(this.return);
}
}
```
- 上面的重點在於 ngOnInit 的時候,先透過 **queryParams** 這個 observable 取得 **return** (如果有的話,沒有就給定 /forums),並設定到 this.return
- 這兒使用的是 router 的 **navigateByUrl** 而非 **navigate**,前者是依我們提供的完整 url 作 routing,後者是會依提供的字串去調整現有的 url
- 詳細的比較請參考[連結](https://stackoverflow.com/questions/45025334/how-to-use-router-navigatebyurl-and-router-navigate-in-angular)
- 調整 AppComponent's 的 template
```html=
<a class="nav-link nav-icon" (
click)="logout()"
*ngIf="!userService.isGuest()">
<clr-icon shape="logout"></clr-icon>
</a>
```
- 登入的圖示會依使用者目前的登入狀態決定
- 而登入狀態又由 userService 的實作決定
- 不過那個實著只是假的,實務上建議還是走正規的驗證
- Secondary Route 目前已經受到 Guard 守護了,但還是要避免登出時沒有關閉的情形發生
- 因此我們要調整 UserService
```typescript=
logout() {
username = '';
guest = true;
localStorage.setItem('username', '');
this.router.navigate([{ outlets: { chat: null }}]);
}
```
- 主要是在登出的時候,順便用注入的 **Router** 將 **chat** 這個 outlet 的 Secondary route 關閉
When you subscribe to the blog, we will send you an e-mail when there are new updates on the site so you wouldn't miss them.
評論