欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

在Angular中使用JWT認(rèn)證方法示例

 更新時(shí)間:2018年09月10日 11:10:57   作者:湯誠(chéng)  
這篇文章主要介紹了在Angular中使用JWT認(rèn)證方法示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧

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

項(xiàng)目地址: grading-system

基于session的認(rèn)證和基于token的認(rèn)證的方式已經(jīng)被廣泛使用。在session認(rèn)證中,服務(wù)端會(huì)存儲(chǔ)一份用戶登錄信息,這份登錄信息會(huì)在響應(yīng)時(shí)傳遞給瀏覽器并保存為Cookie,在下次請(qǐng)求時(shí),會(huì)帶上這份登錄信息,這樣就能識(shí)別請(qǐng)求來(lái)自哪個(gè)用戶。

在基于session的認(rèn)證中,每個(gè)用戶都要生成一份session,這份session通常保存在內(nèi)存中,隨著用戶量的增加,服務(wù)端的開(kāi)銷會(huì)增大,而且對(duì)分布式應(yīng)用不是很友好。

在token認(rèn)證中,服務(wù)端不需要保留用戶認(rèn)證信息。當(dāng)用戶登錄時(shí),服務(wù)器驗(yàn)證用戶信息后會(huì)返回一個(gè)token,這個(gè)token存儲(chǔ)在客戶端,并且在每次請(qǐng)求的請(qǐng)求頭中都帶上這個(gè)token,這樣服務(wù)端驗(yàn)證token后就可以返回?cái)?shù)據(jù)。

JWT(JSON Web Token)是一個(gè)開(kāi)放標(biāo)準(zhǔn)(RFC 7519),它定義了一種緊湊且獨(dú)立的方式,可以在各方之間作為JSON對(duì)象安全地傳輸信息。 此信息可以通過(guò)數(shù)字簽名進(jìn)行驗(yàn)證和信任。特別適用于分布式站點(diǎn)的單點(diǎn)登錄(SSO)場(chǎng)景。

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

JWT 是 JSON Web Tokens 的簡(jiǎn)稱,對(duì)于這個(gè)問(wèn)題最精簡(jiǎn)的回答是,JWT 具有簡(jiǎn)便、緊湊、安全的特點(diǎn),具體來(lái)看:

簡(jiǎn)便:只要用戶登陸后,使用 JWT 認(rèn)證僅需要添加一個(gè) http header 認(rèn)證信息,這可以用一個(gè)函數(shù)簡(jiǎn)單實(shí)現(xiàn),我們會(huì)在后面的例子中看到這一點(diǎn)。

緊湊:JWT token 是一個(gè) base 64 編碼的字符串,包含若干頭部信息及一些必要的數(shù)據(jù),非常簡(jiǎn)單。簽名后的 JWT 字符串通常不超過(guò) 200 字節(jié)。

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

總之你可以有一種安全有效的方式來(lái)認(rèn)證用戶,并且對(duì)所有 api 調(diào)用都進(jìn)行認(rèn)證,而不需要解析復(fù)雜的數(shù)據(jù)結(jié)構(gòu)或者實(shí)現(xiàn)自己的加密算法。

JWT的構(gòu)成

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

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

也就是說(shuō),JWT只是一個(gè)具有以下格式的字符串:

header.payload.signature

頭部

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

header.payload.signature

然后,對(duì)這個(gè)JSON進(jìn)行Base64編碼,形成JWT的第一部分。

ewogICJhbGciOiAiSFMyNTYiLAogICJ0eXAiOiAiSldUIgp9

荷載

JWT的第二部分是荷載,其中包含聲明。 聲明是關(guān)于實(shí)體(通常是用戶)和其他數(shù)據(jù)的聲明。聲明有三種:注冊(cè)的聲明、公開(kāi)的聲明和私有的聲明。

JWT規(guī)范定義了七個(gè)在標(biāo)準(zhǔn)中注冊(cè)的聲明名稱,它們是:

  • iss: JWT簽發(fā)者
  • sub: JWT所面向的用戶
  • aud:接收J(rèn)WT的一方
  • exp:JWT的過(guò)期時(shí)間,這個(gè)過(guò)期時(shí)間必須要大于簽發(fā)時(shí)間
  • nbf:定義在什么時(shí)間之前,該JWT都是不可用的.
  • iat: JWT的簽發(fā)時(shí)間
  • jti: JWT的唯一身份標(biāo)識(shí),主要用來(lái)作為一次性token,從而回避重放攻擊。

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

  • auth_time:身份驗(yàn)證發(fā)生的時(shí)間
  • acr:認(rèn)證上下文類的引用
  • nonce:用于將客戶端會(huì)話與ID Token關(guān)聯(lián)的值

最后,還有私有的聲明名稱,可以使用它們來(lái)傳達(dá)與身份相關(guān)的信息,例如姓名或部門。

由于公共和私人的聲明未注冊(cè),請(qǐng)注意避免名稱沖突。

比如,我們定義一個(gè)palyload:

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

然后將其進(jìn)行base64加密,得到JWT的第二部分:

ewogICJzdWIiOiAiMTIzNDU2Nzg5MCIsCiAgIm5hbWUiOiAidGM5MDExIiwKICAiYWRtaW4iOiB0cnVlLAogICJleHAiOiAxNDQxNTk0NzIyCn0=

簽名

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

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

ewogICJhbGciOiAiSFMyNTYiLAogICJ0eXAiOiAiSldUIgp9.ewogICJzdWIiOiAiMTIzNDU2Nzg5MCIsCiAgIm5hbWUiOiAidGM5MDExIiwKICAiYWRtaW4iOiB0cnVlLAogICJleHAiOiAxNDQxNTk0NzIyCn0=

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

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

使用JWT

一般在會(huì)在請(qǐng)求頭中加入 Authorization ,并加上 Bearer 進(jìn)行標(biāo)注:

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

服務(wù)端會(huì)驗(yàn)證token,如果驗(yàn)證通過(guò)就會(huì)返回相應(yīng)的資源。

不過(guò)要注意,因?yàn)楹奢d是base64編碼,這種編碼可以對(duì)稱解密,所以在荷載中不應(yīng)該存放用戶的敏感信息,比如密碼。所以一般JWT用來(lái)向Web傳遞一些非敏感信息,例如用戶名、所屬部門等。

在Angular中使用JWT

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

服務(wù)端

首先在jwt.io 官網(wǎng)上找到node的JWT的庫(kù): jsonwebtoken 。

可以看到官網(wǎng)把這個(gè)庫(kù)對(duì)標(biāo)準(zhǔn)注冊(cè)聲明字段的支持情況以及加密方式的支持情況都列出來(lái)了。除了這個(gè)庫(kù),還需要使用koa一個(gè)中間件: koa-jwt ,用來(lái)對(duì)HTTP請(qǐng)求進(jìn)行JWT認(rèn)證。你可以通過(guò)下面命令安裝這兩個(gè)庫(kù):

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 方法用來(lái)排除一些不需要進(jìn)行JWT認(rèn)證的api。koa-jwt中間件需要放在路由中間件之前,這樣就可以對(duì)所有路由(除了 unless 中設(shè)置的路由外)進(jìn)行JWT的檢查。只有正確之后才能正確的訪問(wèn)。

除此之外,你還要自定義一個(gè)401錯(cuò)誤處理的中間件,如果沒(méi)有token,或者token失效,該中間件會(huì)給出對(duì)應(yīng)的錯(cuò)誤信息。如果沒(méi)有自定義中間件的話,會(huì)直接將 koa-jwt 暴露的錯(cuò)誤信息直接返回給用戶。

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

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

app.use(errorHandle);

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

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

// 生成 token 返回給客戶端
const token = jsonwebtoken.sign({
  user: {
    workNumber: user.workNumber,
    realName: user.realName,
    group: user.group,
    role: user.role
  },

  // 設(shè)置 token 過(guò)期時(shí)間
  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() 時(shí),需要傳入的 secret 參數(shù),這里的 secret 必須要與 前面設(shè)置 jwt() 中的 secret 一致。

客戶端

在Angular中,我們需要使用 @auth0/angular2-jwt 這個(gè)庫(kù)來(lái)幫助我們?cè)贏ngular中處理JWT:

npm install @auth0/angular-jwt --save

app.module.ts 中引入 JwtModule 這個(gè)模塊(注意,引入該模塊的同時(shí)也要引入 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 :允許發(fā)送認(rèn)證的請(qǐng)求的域名;

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

接著創(chuàng)建一個(gè)全局的 auth.service.ts 服務(wù),方便在登陸的時(shí)候獲取用戶相關(guān)信息及權(quán)限,這個(gè)服務(wù)中有個(gè) login 方法,用來(lái)處理登陸后返回的token信息,并把token存到LocalStorage中,這樣在token失效前,下次用戶登陸時(shí)就不需要輸入用戶名和密碼:

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;
    }
  )
                             );
}

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

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

在這個(gè)服務(wù)中,定義了兩個(gè)變量 loggedInisAdmin ,用來(lái)標(biāo)識(shí)用戶是否登錄和其相應(yīng)的權(quán)限,方便在Angular路由中控制可以訪問(wèn)的視圖。

有登錄當(dāng)然就有登出,登出時(shí)只需把token從LocalStorage中移除,并把幾個(gè)變量重置即可:

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應(yīng)用中就引入了JWT認(rèn)證,當(dāng)然,你也可以不使用 @auth0/angular2-jwt ,自己手寫(xiě)一個(gè)HTTP攔截器,手動(dòng)設(shè)置每次請(qǐng)求的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);
    }
  }
}

不過(guò)這樣的話,token Base64解碼也需要自己手寫(xiě),稍微麻煩一點(diǎn)。

總結(jié)

JWT因?yàn)槭腔贘SON的,所以通用性很強(qiáng),很多語(yǔ)言已經(jīng)存在jwt相關(guān)的庫(kù)。不過(guò)使用JWT的時(shí)候需要注意以下幾點(diǎn):

  • 保存好secret秘鑰,這個(gè)秘鑰只能在服務(wù)端存在
  • 給token設(shè)置一個(gè)過(guò)期時(shí)間,因?yàn)橐坏﹖oken生成,它就永遠(yuǎn)有效,除非token密鑰被更改或過(guò)期
  • 在payload中只能存儲(chǔ)一些業(yè)務(wù)邏輯所必要的非敏感信息

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • AngularJS select加載數(shù)據(jù)選中默認(rèn)值的方法

    AngularJS select加載數(shù)據(jù)選中默認(rèn)值的方法

    下面小編就為大家分享一篇AngularJS select加載數(shù)據(jù)選中默認(rèn)值的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-02-02
  • AngularJS 實(shí)現(xiàn)彈性盒子布局的方法

    AngularJS 實(shí)現(xiàn)彈性盒子布局的方法

    本文給大家?guī)?lái)一段簡(jiǎn)短代碼實(shí)現(xiàn)angularjs彈性布局效果,非常實(shí)用,對(duì)angularjs彈出布局知識(shí)感興趣的朋友可以參考下
    2016-08-08
  • Augularjs-起步詳解

    Augularjs-起步詳解

    下面小編就為大家?guī)?lái)一篇Augularjs-起步詳解。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2016-07-07
  • AngularJS表達(dá)式講解及示例代碼

    AngularJS表達(dá)式講解及示例代碼

    本文主要講解AngularJS表達(dá)式,這里整理了相關(guān)資料和提供示例代碼以及實(shí)現(xiàn)效果圖,有需要的小伙伴可以參考下
    2016-08-08
  • AngularJS的ng-repeat指令與scope繼承關(guān)系實(shí)例詳解

    AngularJS的ng-repeat指令與scope繼承關(guān)系實(shí)例詳解

    這篇文章主要介紹了AngularJS的ng-repeat指令與scope繼承關(guān)系,結(jié)合實(shí)例形式通過(guò)ng-repeat指令詳細(xì)分析了scope繼承關(guān)系,需要的朋友可以參考下
    2017-01-01
  • AngularJS 面試題集錦

    AngularJS 面試題集錦

    本文主要介紹AngularJS的面試題資料整理,這里整理了相關(guān)面試題的資料,幫助大家學(xué)習(xí)理解AngularJS的知識(shí),有興趣的小伙伴可以參考下
    2016-09-09
  • 在AngularJs中設(shè)置請(qǐng)求頭信息(headers)的方法及不同方法的比較

    在AngularJs中設(shè)置請(qǐng)求頭信息(headers)的方法及不同方法的比較

    在AngularJs中有三種方式可以設(shè)置請(qǐng)求頭信息,文中對(duì)每種方法給大家介紹的非常詳細(xì),選擇那種方式可以根據(jù)自己的需求,感興趣的朋友跟隨腳本之家小編一起看看吧
    2018-09-09
  • AngularJs每天學(xué)習(xí)之總體介紹

    AngularJs每天學(xué)習(xí)之總體介紹

    這篇文章主要為大家詳細(xì)介紹了Angularjs總體介紹及數(shù)據(jù)綁定部分內(nèi)容,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-08-08
  • angularjs 表單密碼驗(yàn)證自定義指令實(shí)現(xiàn)代碼

    angularjs 表單密碼驗(yàn)證自定義指令實(shí)現(xiàn)代碼

    這篇文章主要介紹了angularjs 表單密碼驗(yàn)證自定義指令實(shí)現(xiàn)代碼,需要的朋友可以參考下
    2016-10-10
  • 詳解Angular組件之生命周期(二)

    詳解Angular組件之生命周期(二)

    Angular本身監(jiān)督所有Angular組件和指令的生命周期 。為了在開(kāi)發(fā)應(yīng)用程序時(shí)順利進(jìn)行,您必須了解結(jié)果的生命周期。組件是任何Angular應(yīng)用程序的主要構(gòu)建塊。因此,必須了解它們才能理解組件生命周期的處理步驟。只有這樣才能在應(yīng)用程序的開(kāi)發(fā)中實(shí)現(xiàn)。
    2021-05-05

最新評(píng)論