使用angular4和asp.net core 2 web api做個練習專案(四)
Auth Guard
該系統的大部分頁面都應該是使用者登陸以後才可以看見, 沒有登陸的話直接應該跳轉到登陸頁面.
首先建立authguard:
ng g g guards/auth
程式碼:
import { Injectable } from '@angular/core'; import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router'; import { Observable } from 'rxjs/Observable'; import 'rxjs/add/operator/map'; import { User } from 'oidc-client'; import { AuthService } from '../services/auth.service'; @Injectable() export class AuthGuard implements CanActivate { constructor( private router: Router, private authService: AuthService ) { } canActivate(): Observable<boolean> { return this.authService.loginStatusChanged.map((user: User) => { if (user) { return true; } this.authService.login(); return false; }); } }
然後在app.module.ts裡面引用並註冊:
import { AuthGuard } from './guards/auth.guard'; const appRoutes: Routes = [ { path: '', component: DashboardComponent, canActivate: [AuthGuard] }, { path: 'login-callback', component: LoginCallbackComponent }, { path: 'register', component: RegisterComponent }, { path: 'add-client', component: AddClientComponent, canActivate: [AuthGuard] }, { path: 'client/:id', component: ClientDetailsComponent, canActivate: [AuthGuard] }, { path: 'edit-client/:id', component: EditClientComponent, canActivate: [AuthGuard] } ]; providers: [ ClientService, AuthService, AuthGuard ],
需要許可權控制的路由需要加上 canActivate屬性, 它的值是一個數組可以使用多個guards.
別忘了在providers裡面註冊一下.
然後執行.
進入首頁 http://localhost:4200, 如果沒登陸, 那麼直接跳轉到authorization server的登陸頁面.
登入成功後, 會跳轉到login-callback, 這裡有一個地方需要改一下(可能是oidc-client的bug?):
ngOnInit() { this.authService.loginCallBack().subscribe( (user: User) => { if (user) { window.location.href = '/'; } } ); }
使用的是window.location.href='/', 如果使用angular的路由router.navigate跳轉的話會有問題.
登陸成功後跳轉到主頁.
做一些清理工作:
由於使用者註冊是在authorization server進行的, 所以把angular專案中的相關檔案以及app.module裡面的呼叫刪除...
Settings 系統設定
我們需要做一些全域性的設定, 可以全域性控制某些引數, 例如我們的餘額是否可以輸入.
建立settings service:
ng g s services/settings
建立settings model:
ng g interface models/Settings
生成的檔名首字母是小寫的, 首字母還是改成大寫的吧...
Settings.ts:
export interface Settings {
disableBalanceOnAdd?: boolean;
disableBalanceOnEdit?: boolean;
}
settings.service.ts:
import { Injectable } from '@angular/core';
import { Settings } from '../models/Settings';
@Injectable()
export class SettingsService {
private _settings: Settings = {
disableBalanceOnAdd: false,
disableBalanceOnEdit: false
};
constructor() { }
get settings() {
return this._settings;
}
}
然後再app.module.ts裡面註冊:
import { SettingsService } from './services/settings.service';
providers: [
ClientService,
AuthService,
SettingsService,
AuthGuard
]
然後我們使用settings service.
在add-client.component.ts裡面:
import { SettingsService } from '../../services/settings.service';
public disableBalanceOnAdd = false;
constructor(
public flashMessagesService: FlashMessagesService,
public router: Router,
public clientService: ClientService,
public settingsService: SettingsService
) { }
ngOnInit() {
this.disableBalanceOnAdd = this.settingsService.settings.disableBalanceOnAdd;
}
然後執行一下:
發現點選新增按鈕不起作用!!!!, 點選明細也不起作用!!!!
後來發現, 是auth service和auth guard裡面寫錯了, 先修改auth service:
tryGetUser() {
return Observable.fromPromise(this.manager.getUser());
}
把這個方法改成public的.
然後修改: auth guard:
canActivate(): Observable<boolean> {
return this.authService.tryGetUser().map((user: User) => {
if (user) {
return true;
}
this.authService.login();
return false;
});
}
這次再試試, 就沒有問題了. 進入新增客戶頁面.
這個欄位的狀態會根據settings裡面的設定而變化.
同樣在edit-client裡面修改一下:
import { SettingsService } from '../../services/settings.service';
disableBalanceOnEdit = false;
constructor(
public clientService: ClientService,
public router: Router,
public route: ActivatedRoute,
public flashMessagesService: FlashMessagesService,
public settingsService: SettingsService
) { }
ngOnInit() {
this.disableBalanceOnEdit = this.settingsService.settings.disableBalanceOnEdit;
// 獲取ID
this.id = this.route.snapshot.params['id'];
// 獲取Client
this.clientService.getOne(+this.id).subscribe(
client => {
this.client = client;
}
);
}
執行一下, 應該好用!
最後, 做一下Settings頁面
需要改一下setting.serviec, 將使用localstorage來儲存settings:
import { Injectable } from '@angular/core';
import { Settings } from '../models/Settings';
@Injectable()
export class SettingsService {
private _settings: Settings = {
disableBalanceOnAdd: true,
disableBalanceOnEdit: false
};
constructor() {
if (localStorage.getItem('settings')) {
this._settings = JSON.parse(localStorage.getItem('settings'));
}
}
get settings() {
return this._settings;
}
set settings(value: Settings) {
this._settings = value;
localStorage.setItem('settings', JSON.stringify(this._settings));
}
}
然後開啟settings.component.ts:
import { Component, OnInit } from '@angular/core';
import { SettingsService } from '../../services/settings.service';
import { Router } from '@angular/router';
import { FlashMessagesService } from 'angular2-flash-messages';
import { Settings } from '../../models/Settings';
@Component({
selector: 'app-settings',
templateUrl: './settings.component.html',
styleUrls: ['./settings.component.css']
})
export class SettingsComponent implements OnInit {
settings: Settings;
constructor(
private settingsService: SettingsService,
private flashMessagesService: FlashMessagesService,
private router: Router
) { }
ngOnInit() {
this.settings = this.settingsService.settings;
}
onSubmit() {
this.settingsService.settings = this.settings;
this.flashMessagesService.show('Settings 儲存了', { cssClass: 'alert-success', timeout: 4000 });
}
}
這個很簡單.
然後是html:
<div class="row">
<div class="col-md-6">
<a routerLink="/" class="btn btn-link">
<i class="fa fa-arrow-circle-o-left"></i> 回到Dashboard</a>
</div>
<div class="col-md-6">
</div>
</div>
<div class="card">
<div class="card-header">
<h3>編輯 Settings</h3>
</div>
<div class="card-body">
<form (submit)="onSubmit()">
<div class="form-group">
<label for="disableBalanceOnAdd">Disable Blance on Add</label>
<input type="checkbox" id="disableBalanceOnAdd" name="disableBalanceOnAdd" [(ngModel)]="settings.disableBalanceOnAdd">
</div>
<div class="form-group">
<label for="disableBalanceOnEdit">Disable Blance on Edit</label>
<input type="checkbox" id="disableBalanceOnEdit" name="disableBalanceOnEdit" [(ngModel)]="settings.disableBalanceOnEdit">
</div>
<input type="submit" class="btn btn-primary btn-block" value="Submit">
</form>
</div>
</div>
別忘了在app.module裡面新增路由:
const appRoutes: Routes = [
{ path: '', component: DashboardComponent, canActivate: [AuthGuard] },
{ path: 'login-callback', component: LoginCallbackComponent },
{ path: 'add-client', component: AddClientComponent, canActivate: [AuthGuard] },
{ path: 'client/:id', component: ClientDetailsComponent, canActivate: [AuthGuard] },
{ path: 'edit-client/:id', component: EditClientComponent, canActivate: [AuthGuard] },
{ path: 'settings', component: SettingsComponent, canActivate: [AuthGuard] },
{ path: '**', component: PageNotFoundComponent }
];
順便把page Not found的路由也加上, 使用 ** wildcard.
最後在navbar.html 新增上鍊接按鈕:
<li *ngIf="isLoggedIn" class="nav-item">
<a class="nav-link" href="#" routerLink="/settings">Settings </a>
</li>
執行一下試試:
重新整理, 檢視新增和編輯頁面,再重新整理, 應該好用.
這個聯絡專案就到這了.
然後我要用asp.net core 2.0 web api 和 identity server 4 以及 angular 5 做一個專案了(angular 5正式版剛剛出來), 大約 300個頁面......
也許之前還要做一個練習..請各位指教...