摘要:攔截器的官方解釋為攔截機(jī)制是中的主要特性之一。使用這種攔截機(jī)制,你可以聲明一些攔截器,用它們監(jiān)視和轉(zhuǎn)換從應(yīng)用發(fā)送到服務(wù)器的請求。最后調(diào)用,以便這個(gè)請求流能走到下一個(gè)攔截器,并最終傳給后端處理器。
上一節(jié)介紹了好友模塊,這一節(jié)介紹和好友模塊中的控件有關(guān)的三個(gè)服務(wù)程序。
用HttpClient攔截器發(fā)送用戶認(rèn)證信息在進(jìn)入好友模塊之前,需要向服務(wù)器發(fā)送認(rèn)證信息,在這里使用angular的HttpClient攔截器進(jìn)行發(fā)送。
攔截器的官方解釋為:HTTP 攔截機(jī)制是 @angular/common/http 中的主要特性之一。 使用這種攔截機(jī)制,你可以聲明一些攔截器,用它們監(jiān)視和轉(zhuǎn)換從應(yīng)用發(fā)送到服務(wù)器的 HTTP 請求。 攔截器還可以用監(jiān)視和轉(zhuǎn)換從服務(wù)器返回到本應(yīng)用的那些響應(yīng)。 多個(gè)選擇器會(huì)構(gòu)成一個(gè)“請求/響應(yīng)處理器”的雙向鏈表。如果想詳細(xì)了解攔截器,可以看官方文檔
我們利用攔截器在每次向服務(wù)器請求朋友列表時(shí)將認(rèn)證信息加入到頭部。
具體代碼如下:
import { Injectable } from "@angular/core"; import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest } from "@angular/common/http"; import { Observable } from "rxjs/observable"; import { AuthTokenService } from "./authtoken.service"; @Injectable() export class AuthInterceptor implements HttpInterceptor{ constructor( private tokenServ: AuthTokenService ){} intercept(req: HttpRequest,next: HttpHandler) : Observable >{ //獲取認(rèn)證信息 const auth = this.tokenServ.getToken(); //克隆request,加入新的頭信息 const authReq = req.clone({headers:req.headers.set("Authorization", "Bearer " + auth)}); return next.handle(authReq); } }
要實(shí)現(xiàn)攔截器,就要實(shí)現(xiàn)一個(gè)實(shí)現(xiàn)了 HttpInterceptor 接口中的 intercept() 方法的類(AuthInterceptor)。在intercept()方法中先通過AuthTokenService的getToken()方法取得認(rèn)證信息。這些認(rèn)證信息是在登錄或注冊成功后由服務(wù)器發(fā)回來的jwt認(rèn)證信息。服務(wù)器如何發(fā)送這些信息請參考第三節(jié)的內(nèi)容,認(rèn)證信息的內(nèi)容是登錄或認(rèn)證的用戶ID。因?yàn)镠ttpRequest 實(shí)例的屬性卻是只讀(readonly)的,要修改請求信息只能先克隆它。在這里利用clone()方法在請求的頭部信息中加入認(rèn)證信息( clone() 方法的哈希型參數(shù)允許你在復(fù)制出克隆體的同時(shí)改變該請求的某些特定屬性)。最后調(diào)用 next.handle(),以便這個(gè)請求流能走到下一個(gè)攔截器,并最終傳給后端處理器。
最后還需要向模塊這個(gè)攔截器,這個(gè)AuthInterceptor攔截器就是一個(gè)由 Angular 依賴注入 (DI)系統(tǒng)管理的服務(wù),你必須在提供 HttpClient 的同一個(gè)(或其各級父注入器)注入器中提供這些攔截器。在好友模塊的providers中加入
{ provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi:true }
現(xiàn)在在好友模塊中每個(gè)發(fā)送到服務(wù)器的請求都會(huì)在頭部加上認(rèn)證信息。
補(bǔ)充內(nèi)容:服務(wù)器jwt認(rèn)證中間件
express的jwt中間件定義代碼如下:
var expressJwt = require("express-jwt"); //使用jwt攔截 app.use(expressJwt({ secret: "secret" })); //處置jwt異常 app.use(function (err, req, res, next) { if (err.name === "UnauthorizedError") { res.status(401).send({ "code": 401, "msg": "invalid token" }); } }); app.use("/friends", friends);
一定要把處理friends訪問的路由放到j(luò)wt中間件后面,不然jwt無法進(jìn)行驗(yàn)證。
利用路由守衛(wèi)保證未登錄用戶無法訪問好友信息在上一節(jié)介紹路由時(shí),在路由配置中加入了canActivate: [AuthGuardService],這是angular路由守衛(wèi)服務(wù),路由守衛(wèi)的作用在官方文檔中的解釋如下:
現(xiàn)在,任何用戶都能在任何時(shí)候?qū)Ш降饺魏蔚胤健?但有時(shí)候這樣是不對的。
該用戶可能無權(quán)導(dǎo)航到目標(biāo)組件。
可能用戶得先登錄(認(rèn)證)。
在顯示目標(biāo)組件前,你可能得先獲取某些數(shù)據(jù)。
在離開組件前,你可能要先保存修改。
你可能要詢問用戶:你是否要放棄本次更改,而不用保存它們?
你可以往路由配置中添加守衛(wèi),來處理這些場景。
守衛(wèi)返回一個(gè)值,以控制路由器的行為:
如果它返回 true,導(dǎo)航過程會(huì)繼續(xù)
如果它返回 false,導(dǎo)航過程會(huì)終止,且用戶會(huì)留在原地。
在這里我們利用路由守衛(wèi)要求用戶先登錄才能導(dǎo)航到birthday模塊中的控件。
代碼如下:
import { Injectable } from "@angular/core"; import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from "@angular/router"; import { UserService } from "./user.service"; import { AuthTokenService } from "./authtoken.service"; @Injectable() export class AuthGuardService implements CanActivate { constructor( private tokenServe: AuthTokenService, private router: Router) { } canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) { if (this.tokenServe.getToken() !== null) { return true; } this.router.navigate(["/login"]); return false; } }
路由守衛(wèi)類也是一個(gè)注入服務(wù)類,它需要實(shí)現(xiàn)CanActivate接口的canActivate()方法。canActivate()方法實(shí)現(xiàn)了守衛(wèi)代碼。代碼很簡單,從AuthTokenService類的getToken()中獲取認(rèn)證信息的值,如果有就返回true,如果沒有就導(dǎo)航到登錄頁面。并返回false。
最后記住在birthday模塊中providers中加入AuthGuardService。
BirthdayService類為birthday模塊提供了數(shù)據(jù)服務(wù),代碼如下:
import { Injectable } from "@angular/core"; import { HttpClient, HttpHeaders,HttpErrorResponse } from "@angular/common/http"; import { UserService } from "../user.service"; import "rxjs/add/operator/map"; export class Friend { constructor( public fid: number, public fname: string, public fbirth: Date, public fnumber: string, public femail: string, public fgroup: string, public state: string, public photo: string, public uid:number ) { } } @Injectable() export class BirthdayService { constructor( private userServ: UserService, private http: HttpClient) { } //獲取全部朋友信息 getFriends() { return this.http.get("http://localhost:3000/friends/friend-list", { observe: "response"});} //獲取單個(gè)朋友信息 getFriend(id: number | string) { return this.getFriends().map(res => { if (res.body["code"] === "200") { return res.body["results"].find(result => result.fid === +id);} }); } //修改朋友信息 editFriend(friend: Friend){ const body = {"value":friend,"operate":"edit"}; return this.http.post("http://localhost:3000/friends/editfriend",body); } //新建朋友信息 newFriend(friend: Friend){ const body = {"value":friend,"operate":"new"}; return this.http.post("http://localhost:3000/friends/editfriend", body); } //刪除好友 deleteFriend(friend:Friend){ const body = {"value":friend, "operate":"delete"}; return this.http.post("http://localhost:3000/friends/editfriend",body); } //錯(cuò)誤處理 handleError(err: HttpErrorResponse): string { if (err.error instanceof Error) { return "發(fā)生錯(cuò)誤,錯(cuò)誤信息:" + err.error.message; } else { console.log(`Backend returned code ${err.status}, body was: ${err.error["msg"]}`); return err.error["msg"]; } } }
首先在類外定義了一個(gè)Friend類,在這個(gè)類中定義了friend信息。BirthdayService類的主要功能有6部分:
獲取全部朋友信息。通過HttpClient的get方法發(fā)送獲取到全部的friend信息的請求。
獲取單個(gè)朋友信息。getFriends()方法返回的是一個(gè)Observable對象,利用Observable的map()函數(shù)的回調(diào)找到對應(yīng)id的單個(gè)friend對象,并繼續(xù)發(fā)射Observable對象。
修改朋友信息。將修改后的friend信息post到服務(wù)器。在發(fā)送的body中,除了修改后的friend對象,還發(fā)送了一個(gè)字符串屬性:"operate":"edit",用于區(qū)分是修改friend還是新建friend,這了的edit代表修改信息。(具體的服務(wù)器操作代碼將在下一章介紹)。
新建朋友信息。和修改friend信息同理,只不過將body中的"operate"改為"new"。
刪除好友。也和修改friend信息同理,只不過將body中的"operate"改為"delete"。
錯(cuò)誤處理。如果是客戶端(angular代碼)出了錯(cuò),會(huì)拋出一個(gè) Error 類型的異常,由此判斷如果錯(cuò)誤的類型是Error類型,就表示前端出錯(cuò),返回一條錯(cuò)誤信息:"發(fā)生錯(cuò)誤,錯(cuò)誤信息:" + err.error.message;。如果是后端出錯(cuò),就打印出錯(cuò)誤狀態(tài)和信息。
關(guān)于birthday模塊的服務(wù)程序就介紹完了。下一章將要介紹服務(wù)器端express框架如何處理這些請求。今天將我的代碼傳到了github上,方便大家參考。地址如下:
前端:https://github.com/db991400/b...
后端:https://github.com/db991400/b...
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/94572.html
摘要:后臺注冊成功后,會(huì)返回狀態(tài)的認(rèn)證信息。后臺數(shù)據(jù)的處理,詳見利用和構(gòu)建一個(gè)簡單的網(wǎng)站三訪問。在這個(gè)方法中分別針對這兩種錯(cuò)誤進(jìn)行處理。 上一節(jié)簡單介紹了一下利用angular構(gòu)建的主路由模塊,根據(jù)上一節(jié)的介紹,主頁面加載時(shí)直接跳轉(zhuǎn)到用戶管理界面,下面就來介紹一下用戶管理模塊。啟動(dòng)應(yīng)用后,初始界面應(yīng)該是這樣的: showImg(https://segmentfault.com/img/bV3...
摘要:后臺注冊成功后,會(huì)返回狀態(tài)的認(rèn)證信息。后臺數(shù)據(jù)的處理,詳見利用和構(gòu)建一個(gè)簡單的網(wǎng)站三訪問。在這個(gè)方法中分別針對這兩種錯(cuò)誤進(jìn)行處理。 上一節(jié)簡單介紹了一下利用angular構(gòu)建的主路由模塊,根據(jù)上一節(jié)的介紹,主頁面加載時(shí)直接跳轉(zhuǎn)到用戶管理界面,下面就來介紹一下用戶管理模塊。啟動(dòng)應(yīng)用后,初始界面應(yīng)該是這樣的: showImg(https://segmentfault.com/img/bV3...
摘要:上一章通過用戶注冊講解了響應(yīng)式表單,這章主要講解如何向服務(wù)器提交注冊數(shù)據(jù)并導(dǎo)航到好友信息模塊。利用的方法將這個(gè)憑證存儲(chǔ)到本地。針對一個(gè)進(jìn)行數(shù)據(jù)存儲(chǔ)。當(dāng)用戶關(guān)閉瀏覽器窗口后,數(shù)據(jù)會(huì)被刪除。 上一章通過用戶注冊講解了響應(yīng)式表單ReactiveForm,這章主要講解如何向服務(wù)器提交注冊數(shù)據(jù)并導(dǎo)航到好友信息模塊。 提交注冊信息 向服務(wù)器提交信息是通過模板中標(biāo)簽中的(ngSubmit)=onSu...
閱讀 1794·2023-04-25 22:42
閱讀 2218·2021-09-22 15:16
閱讀 3495·2021-08-30 09:44
閱讀 493·2019-08-29 16:44
閱讀 3316·2019-08-29 16:20
閱讀 2521·2019-08-29 16:12
閱讀 3395·2019-08-29 16:07
閱讀 673·2019-08-29 15:08