亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > JavaScript > 正文

在Angular中使用JWT認證方法示例

2019-11-19 12:58:56
字體:
來源:轉載
供稿:網友

本文介紹了在Angular中使用JWT認證方法示例,分享給大家,具體如下:

項目地址: grading-system

基于session的認證和基于token的認證的方式已經被廣泛使用。在session認證中,服務端會存儲一份用戶登錄信息,這份登錄信息會在響應時傳遞給瀏覽器并保存為Cookie,在下次請求時,會帶上這份登錄信息,這樣就能識別請求來自哪個用戶。

在基于session的認證中,每個用戶都要生成一份session,這份session通常保存在內存中,隨著用戶量的增加,服務端的開銷會增大,而且對分布式應用不是很友好。

在token認證中,服務端不需要保留用戶認證信息。當用戶登錄時,服務器驗證用戶信息后會返回一個token,這個token存儲在客戶端,并且在每次請求的請求頭中都帶上這個token,這樣服務端驗證token后就可以返回數據。

JWT(JSON Web Token)是一個開放標準(RFC 7519),它定義了一種緊湊且獨立的方式,可以在各方之間作為JSON對象安全地傳輸信息。 此信息可以通過數字簽名進行驗證和信任。特別適用于分布式站點的單點登錄(SSO)場景。

JWT 是什么,為何要使用 JWT?

JWT 是 JSON Web Tokens 的簡稱,對于這個問題最精簡的回答是,JWT 具有簡便、緊湊、安全的特點,具體來看:

簡便:只要用戶登陸后,使用 JWT 認證僅需要添加一個 http header 認證信息,這可以用一個函數簡單實現,我們會在后面的例子中看到這一點。

緊湊:JWT token 是一個 base 64 編碼的字符串,包含若干頭部信息及一些必要的數據,非常簡單。簽名后的 JWT 字符串通常不超過 200 字節。

安全:JWT 可以使用 RSA 或 HMAC 加密算法進行加密,確保 token 有效且防止篡改。

總之你可以有一種安全有效的方式來認證用戶,并且對所有 api 調用都進行認證,而不需要解析復雜的數據結構或者實現自己的加密算法。

JWT的構成

JWT由 . 分隔的三個部分組成,它們是:

  • 頭部(Header)
  • 荷載(Playload)
  • 簽名(Signature)

也就是說,JWT只是一個具有以下格式的字符串:

header.payload.signature

頭部

頭部通常由兩部分組成:令牌的類型(即JWT)以及正在使用的散列算法,例如HMAC SHA256或RSA。

header.payload.signature

然后,對這個JSON進行Base64編碼,形成JWT的第一部分。

ewogICJhbGciOiAiSFMyNTYiLAogICJ0eXAiOiAiSldUIgp9

荷載

JWT的第二部分是荷載,其中包含聲明。 聲明是關于實體(通常是用戶)和其他數據的聲明。聲明有三種:注冊的聲明、公開的聲明和私有的聲明。

JWT規范定義了七個在標準中注冊的聲明名稱,它們是:

  • iss: JWT簽發者
  • sub: JWT所面向的用戶
  • aud:接收JWT的一方
  • exp:JWT的過期時間,這個過期時間必須要大于簽發時間
  • nbf:定義在什么時間之前,該JWT都是不可用的.
  • iat: JWT的簽發時間
  • jti: JWT的唯一身份標識,主要用來作為一次性token,從而回避重放攻擊。

對于特定情況,可以使用公共的聲明名稱。 這些包括:

  • auth_time:身份驗證發生的時間
  • acr:認證上下文類的引用
  • nonce:用于將客戶端會話與ID Token關聯的值

最后,還有私有的聲明名稱,可以使用它們來傳達與身份相關的信息,例如姓名或部門。

由于公共和私人的聲明未注冊,請注意避免名稱沖突。

比如,我們定義一個palyload:

{ "sub": "1234567890", "name": "tc9011", "admin": true, "exp": 1441594722}

然后將其進行base64加密,得到JWT的第二部分:

ewogICJzdWIiOiAiMTIzNDU2Nzg5MCIsCiAgIm5hbWUiOiAidGM5MDExIiwKICAiYWRtaW4iOiB0cnVlLAogICJleHAiOiAxNDQxNTk0NzIyCn0=

簽名

簽名由base64編碼后的頭、base64編碼后的荷載和secret組成。

例如,將上面的兩個編碼后的字符串都用句號 . 連接在一起(頭部在前),就形成了:

ewogICJhbGciOiAiSFMyNTYiLAogICJ0eXAiOiAiSldUIgp9.ewogICJzdWIiOiAiMTIzNDU2Nzg5MCIsCiAgIm5hbWUiOiAidGM5MDExIiwKICAiYWRtaW4iOiB0cnVlLAogICJleHAiOiAxNDQxNTk0NzIyCn0=

然后,將上面拼接完的字符串用secret作為秘鑰進行HS256加密。

HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)

使用JWT

一般在會在請求頭中加入 Authorization ,并加上 Bearer 進行標注:

fetch('api/v1/user/1', { headers: {  'Authorization': 'Bearer ' + token }})

服務端會驗證token,如果驗證通過就會返回相應的資源。

不過要注意,因為荷載是base64編碼,這種編碼可以對稱解密,所以在荷載中不應該存放用戶的敏感信息,比如密碼。所以一般JWT用來向Web傳遞一些非敏感信息,例如用戶名、所屬部門等。

在Angular中使用JWT

這里我們以Angular6和koa2(使用TypeScript)為例,介紹一下如何在你的Angular應用中使用JWT。

服務端

首先在jwt.io 官網上找到node的JWT的庫: jsonwebtoken 。

可以看到官網把這個庫對標準注冊聲明字段的支持情況以及加密方式的支持情況都列出來了。除了這個庫,還需要使用koa一個中間件: koa-jwt ,用來對HTTP請求進行JWT認證。你可以通過下面命令安裝這兩個庫:

npm i koa-jwt jsonwebtoken --save

app.ts 中:

import * as jwt from 'koa-jwt';app.use(jwt({   secret: Secret  }).unless({   path: [///register/, ///login/, ///groups/],  }));

這里的secret就是你自己定義的秘鑰, unless 方法用來排除一些不需要進行JWT認證的api。koa-jwt中間件需要放在路由中間件之前,這樣就可以對所有路由(除了 unless 中設置的路由外)進行JWT的檢查。只有正確之后才能正確的訪問。

除此之外,你還要自定義一個401錯誤處理的中間件,如果沒有token,或者token失效,該中間件會給出對應的錯誤信息。如果沒有自定義中間件的話,會直接將 koa-jwt 暴露的錯誤信息直接返回給用戶。

export const errorHandle = (ctx, next) => { return next().catch((err) => {  if (err.status === 401) {   ctx.status = 401;   handleError({ctx, message: '登錄過期,請重新登錄', err: err.originalError ? err.originalError.message : err.message});  } else {   throw err;  } });};

然后把這個中間件放在koa-jwt之前:

app.use(errorHandle);app.use(jwt({  secret: Secret}).unless({  path: [///register/, ///login/, ///groups/],}));

在用戶登陸時候,生成token,返回給客戶端:

// 生成 token 返回給客戶端const token = jsonwebtoken.sign({  user: {    workNumber: user.workNumber,    realName: user.realName,    group: user.group,    role: user.role  },  // 設置 token 過期時間  exp: Math.floor(Date.now() / 1000) + (60 * 60 * 24),  // 1天}, Secret);handleSuccess({  ctx,  message: '登陸成功!',  response: {    token,    lifeTime: Math.floor(Date.now() / 1000) + (60 * 60 * 24)  // 1天  }});

需要注意的是,在使用 jsonwebtoken.sign() 時,需要傳入的 secret 參數,這里的 secret 必須要與 前面設置 jwt() 中的 secret 一致。

客戶端

在Angular中,我們需要使用 @auth0/angular2-jwt 這個庫來幫助我們在Angular中處理JWT:

npm install @auth0/angular-jwt --save

app.module.ts 中引入 JwtModule 這個模塊(注意,引入該模塊的同時也要引入 HttpClientModule 模塊):

import { JwtModule } from '@auth0/angular-jwt';import { HttpClientModule } from '@angular/common/http';export function tokenGetter(){ return localStorage.getItem('token');}@NgModule({ bootstrap: [AppComponent], imports: [  // ...  HttpClientModule,  JwtModule.forRoot({   config: {    tokenGetter: tokenGetter,    whitelistedDomains: ['localhost:3001'],    blacklistedRoutes: ['localhost:3001/auth/']   }  }) ]})export class AppModule {}

JwtModuleconfig 中:

tokenGetter :從localStorage中獲取token;

whitelistedDomains :允許發送認證的請求的域名;

blacklistedRoutes :你不希望替換header中 Authorization 信息的api列表。

接著創建一個全局的 auth.service.ts 服務,方便在登陸的時候獲取用戶相關信息及權限,這個服務中有個 login 方法,用來處理登陸后返回的token信息,并把token存到LocalStorage中,這樣在token失效前,下次用戶登陸時就不需要輸入用戶名和密碼:

login(loginInfo: LoginInfo): Observable<boolean> {  return this.passportService.postLogin(loginInfo).pipe(map(    (res: LoginRes) => {      // 登陸成功后獲取token,并存到localStorage      this.storageService.setLocalStorage('token', res.token);      const decodedUser = this.decodeUserFromToken(res.token);      this.setCurrentUser(decodedUser);      this.msg.success('登錄成功!');      return this.loggedIn;    }  )                             );}

在這個 login 方法中, decodeUserFromToken 封裝了 @auth0/angular2-jwt 中提供的 decodeToken 方法,注意 decodeToken 方法解析出來的只是服務端 jsonwebtoken.sign() 中的JSON對象,所以需要通過 . 操作獲取 jsonwebtoken.sign() 中定義的 user

decodeUserFromToken(token): User {  return this.jwtHelperService.decodeToken(token).user;}

在這個服務中,定義了兩個變量 loggedInisAdmin ,用來標識用戶是否登錄和其相應的權限,方便在Angular路由中控制可以訪問的視圖。

有登錄當然就有登出,登出時只需把token從LocalStorage中移除,并把幾個變量重置即可:

logout(): void {  this.storageService.removeLocalStorage('token');  this.loggedIn = false;  this.isAdmin = false;  this.currentUser = new User();}

AuthService 的完整代碼如下:

import { Injectable, Injector } from '@angular/core';import { Router } from '@angular/router';import { JwtHelperService } from '@auth0/angular-jwt';import { Observable } from 'rxjs';import { map } from 'rxjs/operators';import { LoginInfo, LoginRes, User } from '../../views/passport/interfaces/passport';import { PassportService } from '../../views/passport/services/passport.service';import { StorageService } from '../storage/storage.service';import { NzMessageService } from 'ng-zorro-antd';@Injectable()export class AuthService { public loggedIn = false; public isAdmin = false; public currentUser: User = new User(); constructor(private jwtHelperService: JwtHelperService,       private router: Router,       private injector: Injector,       private passportService: PassportService,       private storageService: StorageService) {  const token = localStorage.getItem('token');  if (token) {   const decodedUser = this.decodeUserFromToken(token);   this.setCurrentUser(decodedUser);  } } get msg(): NzMessageService {  return this.injector.get(NzMessageService); } login(loginInfo: LoginInfo): Observable<boolean> {  return this.passportService.postLogin(loginInfo).pipe(map(   (res: LoginRes) => {     this.storageService.setLocalStorage('token', res.token);     const decodedUser = this.decodeUserFromToken(res.token);     this.setCurrentUser(decodedUser);     this.msg.success('登錄成功!');     return this.loggedIn;    }   )  ); } logout(): void {  this.storageService.removeLocalStorage('token');  this.loggedIn = false;  this.isAdmin = false;  this.currentUser = new User(); } decodeUserFromToken(token): User {  return this.jwtHelperService.decodeToken(token).user; } setCurrentUser(decodedUser): void {  this.loggedIn = true;  this.currentUser.workNumber = decodedUser.workNumber;  this.currentUser.realName = decodedUser.realName;  this.currentUser.group = decodedUser.group;  this.currentUser.role = decodedUser.role;  this.isAdmin = decodedUser.role > 10;  delete decodedUser.role; }}

至此,在你的Angular應用中就引入了JWT認證,當然,你也可以不使用 @auth0/angular2-jwt ,自己手寫一個HTTP攔截器,手動設置每次請求的header:

@Injectable()export class AuthInterceptor implements HttpInterceptor {  intercept(req: HttpRequest<any>,       next: HttpHandler): Observable<HttpEvent<any>> {    const token = localStorage.getItem("token");    if (token) {      const cloned = req.clone({        headers: req.headers.set("Authorization",          "Bearer " + token)      });      return next.handle(cloned);    }    else {      return next.handle(req);    }  }}

不過這樣的話,token Base64解碼也需要自己手寫,稍微麻煩一點。

總結

JWT因為是基于JSON的,所以通用性很強,很多語言已經存在jwt相關的庫。不過使用JWT的時候需要注意以下幾點:

  • 保存好secret秘鑰,這個秘鑰只能在服務端存在
  • 給token設置一個過期時間,因為一旦token生成,它就永遠有效,除非token密鑰被更改或過期
  • 在payload中只能存儲一些業務邏輯所必要的非敏感信息

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
精品高清一区二区三区| 亚洲欧美日韩中文在线| 91久久精品国产91性色| 国产丝袜视频一区| 自拍视频国产精品| 一区二区三区日韩在线| 日韩欧美中文字幕在线观看| 91亚洲午夜在线| 日韩性生活视频| 欧美亚洲国产另类| 国产成人福利网站| 日本高清视频精品| 亚洲第一偷拍网| 日韩免费电影在线观看| 日韩精品视频在线观看网址| 精品露脸国产偷人在视频| 欧美一区二区三区……| 国产有码在线一区二区视频| 欧美日韩一区二区三区在线免费观看| 精品爽片免费看久久| 欧美成年人网站| 亚洲第一精品电影| 欧美另类极品videosbestfree| 欧美亚洲在线播放| 亚洲男人天堂视频| 韩国美女主播一区| 国产精品永久免费观看| 亚洲精品国产精品乱码不99按摩| 久久久久一本一区二区青青蜜月| 最近2019中文字幕一页二页| 色偷偷av一区二区三区| 91香蕉亚洲精品| 亚洲网站在线观看| 国产一区二区在线免费| 欧美大尺度电影在线观看| 国外成人免费在线播放| 亚洲已满18点击进入在线看片| 色综合久久悠悠| 亚洲欧美国产精品| 亚洲影院高清在线| 九九热这里只有精品6| 欧美黑人xxxⅹ高潮交| 亚洲iv一区二区三区| 亚洲欧美激情视频| 国产精品视频一| 国产亚洲欧洲黄色| 中文字幕日韩欧美精品在线观看| 最近2019中文免费高清视频观看www99| 久久韩国免费视频| 久久久久国产一区二区三区| 日本精品视频网站| 日韩的一区二区| 成人两性免费视频| 精品久久久久久久久中文字幕| 欧美性黄网官网| 欧美第一黄网免费网站| 尤物99国产成人精品视频| 欧美日本啪啪无遮挡网站| 国产精品久久久91| 久久精品国产久精国产思思| 国产精品久久久久久久久久久久| 国产亚洲精品日韩| 国产精品视频xxx| 国产精品久久久久久五月尺| 美女视频黄免费的亚洲男人天堂| 成人黄色av免费在线观看| 在线日韩av观看| 精品电影在线观看| 成人免费视频在线观看超级碰| 日韩亚洲在线观看| 国产精品免费在线免费| 日本一区二区不卡| 欧美日韩国产丝袜另类| 亚洲xxxx在线| 国产欧美日韩专区发布| 欧美大肥婆大肥bbbbb| 午夜精品视频在线| 国产精欧美一区二区三区| 色综合久久悠悠| 久久综合国产精品台湾中文娱乐网| 精品久久久久久| 国产91精品视频在线观看| 午夜美女久久久久爽久久| 欧美激情综合亚洲一二区| 欧美精品在线免费观看| 中文亚洲视频在线| 国产有码在线一区二区视频| 日韩一区二区在线视频| 国产日韩欧美日韩| 国产成人精品日本亚洲| 亚洲性猛交xxxxwww| 欧美精品制服第一页| 97在线视频免费播放| 国产拍精品一二三| 伊人久久大香线蕉av一区二区| 国产情人节一区| 日韩激情第一页| 日韩中文字幕精品| 久久久久久九九九| 精品无人区太爽高潮在线播放| 亚洲精品av在线| 国产精品成人免费视频| 久久99精品久久久久久青青91| 日韩亚洲第一页| 欧美激情视频在线| 精品国产乱码久久久久久天美| 国内精品在线一区| 欧美另类在线观看| 成人中文字幕+乱码+中文字幕| 亚洲福利视频专区| www.美女亚洲精品| 国产精品高潮呻吟视频| 久久免费国产视频| 久久视频在线看| 欧美另类交人妖| 成年人精品视频| 国产亚洲视频中文字幕视频| 精品久久久久久久大神国产| 久久频这里精品99香蕉| 欧美日韩在线一区| 91久久在线观看| 一本久久综合亚洲鲁鲁| 国产成人在线一区二区| 精品久久久久久久大神国产| 日本精品免费一区二区三区| 一区二区av在线| 高清一区二区三区日本久| 国语自产精品视频在线看抢先版图片| 欧美成人午夜激情在线| 欧美大片在线免费观看| 成人网中文字幕| 亚洲夜晚福利在线观看| 午夜精品久久久久久久久久久久| 中文日韩在线观看| 国产精品99久久99久久久二8| 精品亚洲aⅴ在线观看| 九色精品免费永久在线| 久久久久久免费精品| 国产一区二区在线播放| 日韩成人黄色av| 91国内精品久久| 亚洲开心激情网| 国产欧美va欧美va香蕉在| 日韩欧美在线播放| 中文字幕一区二区三区电影| 久久久久久国产精品三级玉女聊斋| 亚洲无限乱码一二三四麻| 欧美性色19p| 亚洲综合第一页| 欧美在线激情网| 欧美一级在线播放| 久久久久久亚洲精品| 一区二区欧美日韩视频| 最近2019中文免费高清视频观看www99| 草民午夜欧美限制a级福利片| 亚洲精品xxx| 综合激情国产一区| 国产精品亚洲激情| 欧美高清videos高潮hd| 久久精品2019中文字幕| 色偷偷av一区二区三区| 91精品国产高清久久久久久| 欧美精品xxx| 欧美日本在线视频中文字字幕|