Token到底是什么噪窘?!

隨著Web應(yīng)用的發(fā)展,為了保證API通信的安全性倔监,很多項(xiàng)目在進(jìn)行設(shè)計(jì)時(shí)會(huì)采用JSON Web TokenJWT)的解決方案直砂。

JWT是一種開(kāi)放標(biāo)準(zhǔn)(RFC 7519),它定義了一種緊湊且自包含的方式浩习,用于在各方之間安全地傳輸信息作為JSON對(duì)象静暂。這種信息可以被驗(yàn)證和信任,因?yàn)樗菙?shù)字簽名的谱秽。

那么JWT中的Token到底是什么洽蛀?接下來(lái),我們將以登錄功能為例進(jìn)行Token的分析疟赊。

登錄流程

很多小伙伴對(duì)登錄的流程已經(jīng)很熟悉了郊供,我們來(lái)看一個(gè)最基本的后臺(tái)系統(tǒng)的登錄流程

登錄流程圖.png

流程圖很清楚了,接下來(lái)我們使用 V2Koa 來(lái)實(shí)現(xiàn)一個(gè)登錄過(guò)程近哟,來(lái)看看Token到底是什么

Vue2 + Koa 實(shí)現(xiàn)登錄

前端代碼

1. 前端點(diǎn)擊事件

數(shù)據(jù)的校驗(yàn)就忽略掉驮审,感興趣的同學(xué)可自行書寫或者找我要源碼,直接看點(diǎn)擊事件

handleLogin() {
  this.$refs.loginForm.validate((valid) => {
    if (valid) {
      this.loading = true;
      // 這里使用了VueX
      this.$store
        .dispatch("user/login", this.loginForm)
        .then(() => {
        this.$router.push({ path: this.redirect || "/" });
        this.loading = false;
      })
        .catch(() => {
        this.loading = false;
      });
    } else {
      return false;
    }
  });
}

2. Vuex中的action

校驗(yàn)通過(guò)后觸發(fā)VueXUser模塊的Login方法:

async login(context, userInfo) {
  const users = {
    username: userInfo.mobile,
    password: userInfo.password
  }
  const token = await login(users)
  // 在這里大家可以對(duì)返回的數(shù)據(jù)進(jìn)行更詳細(xì)的邏輯處理
  context.commit('SET_TOKEN', token)
  setToken(token)
}

3. 封裝的接口

export function login(data) {
  return request({
    url: '/login',
    method: 'post',
    data
  })
}

以上三步吉执,是我們從前端向后端發(fā)送了請(qǐng)求并攜帶著用戶名和密碼疯淫,接下來(lái),我們來(lái)看看Koa中是如何處理前端的請(qǐng)求的

Koa 處理請(qǐng)求

首先介紹一下Koa

Koa 基于Node.js平臺(tái)戳玫,由 Express 幕后的原班人馬打造熙掺,是一款新的服務(wù)端 web 框架

Koa的使用極其簡(jiǎn)單,感興趣的小伙伴可以參考官方文檔嘗試用一下

Koa官網(wǎng):https://koa.bootcss.com/index.html#introduction

1. 技術(shù)說(shuō)明

在當(dāng)前案例的koa中咕宿,使用到了jsonwebtoken的依賴包幫助我們?nèi)ゼ用苌珊徒饷?code>Token

2. 接口處理

const { login } = require("../app/controller/user")
const jwt = require("jsonwebtoken")
const SECRET = 'test_';
router.post('/login', async (ctx, next) => {
    const { username, password } = ctx.request.body
    // 這里是調(diào)用Controller中的login方法來(lái)跟數(shù)據(jù)庫(kù)中的數(shù)據(jù)作對(duì)比适掰,可忽略
    const userList = await login(username, password)
    
    if (!userList) {
        // 這里的errorModel是自己封裝的處理錯(cuò)誤的模塊
        ctx.body = new errorModel('用戶名或密碼錯(cuò)誤', '1001')
        return
    }
  
    // ↓↓↓↓↓↓↓↓↓↓↓↓↓↓ ※ 重點(diǎn)看這里 ※ ↓↓↓↓↓↓↓↓↓↓↓↓↓↓
    const token = jwt.sign({ userList }, SECRET, { expiresIn: "1h" })
    
    ctx.body = {
        success: true,
        state: 200,
        message: 'login success',
        data: token
    };
    return;
})

關(guān)于 JWT

上面的重點(diǎn)代碼大家看到了,接下來(lái)具體給大家解釋下JWT

Jwt由三部分組成:header荠列、payload类浪、signature

export interface Jwt {
    header: JwtHeader;
    payload: JwtPayload | string;
    signature: string;
}

header頭部

里面的包含的內(nèi)容有很多,比如用于指定加密算法的alg肌似、指定加密類型的typ费就,全部參數(shù)如下所示:

export interface JwtHeader {
    alg: string | Algorithm;
    typ?: string | undefined;
    cty?: string | undefined;
    crit?: Array<string | Exclude<keyof JwtHeader, 'crit'>> | undefined;
    kid?: string | undefined;
    jku?: string | undefined;
    x5u?: string | string[] | undefined;
    'x5t#S256'?: string | undefined;
    x5t?: string | undefined;
    x5c?: string | string[] | undefined;
}

payload負(fù)載

payload使我們存放信息的地方,里面包含了簽發(fā)者川队、過(guò)期時(shí)間力细、簽發(fā)時(shí)間等信息

export interface JwtPayload {
    [key: string]: any;
    iss?: string | undefined;
    sub?: string | undefined;
    aud?: string | string[] | undefined;
    exp?: number | undefined;
    nbf?: number | undefined;
    iat?: number | undefined;
    jti?: string | undefined;
}

signature簽名

signature需要使用編碼后的headerpayload以及我們提供的一個(gè)密鑰(SECRET),然后使用header 中指定的簽名算法進(jìn)行簽名

關(guān)于 jwt.sign()

jwt.sign()方法固额,需要三個(gè)基本參數(shù)和一個(gè)可選參數(shù):payload眠蚂、secretOrPrivateKeyoptions和一個(gè)callback

export function sign(
    payload: string | Buffer | object,
    secretOrPrivateKey: Secret,
    options: SignOptions,
    callback: SignCallback,
): void;

payload是我們需要加密的一些信息斗躏,這個(gè)參數(shù)對(duì)應(yīng)上面koa代碼中的{ userList }逝慧,而userList則是我從數(shù)據(jù)庫(kù)中查詢得到的數(shù)據(jù)結(jié)果

secretOrPrivateKey則是我們自己定義的秘鑰,用來(lái)后續(xù)驗(yàn)證Token時(shí)所用

options選項(xiàng)中有很多內(nèi)容,例如加密算法algorithm笛臣、有效期expiresIn等等

export interface SignOptions {
    /**
     * Signature algorithm. Could be one of these values :
     * - HS256:    HMAC using SHA-256 hash algorithm (default)
     * - HS384:    HMAC using SHA-384 hash algorithm
     * - HS512:    HMAC using SHA-512 hash algorithm
     * - RS256:    RSASSA using SHA-256 hash algorithm
     * - RS384:    RSASSA using SHA-384 hash algorithm
     * - RS512:    RSASSA using SHA-512 hash algorithm
     * - ES256:    ECDSA using P-256 curve and SHA-256 hash algorithm
     * - ES384:    ECDSA using P-384 curve and SHA-384 hash algorithm
     * - ES512:    ECDSA using P-521 curve and SHA-512 hash algorithm
     * - none:     No digital signature or MAC value included
     */
    algorithm?: Algorithm | undefined;
    keyid?: string | undefined;
    /** expressed in seconds or a string describing a time span [zeit/ms](https://github.com/zeit/ms.js).  Eg: 60, "2 days", "10h", "7d" */
    expiresIn?: string | number | undefined;
    /** expressed in seconds or a string describing a time span [zeit/ms](https://github.com/zeit/ms.js).  Eg: 60, "2 days", "10h", "7d" */
    notBefore?: string | number | undefined;
    audience?: string | string[] | undefined;
    subject?: string | undefined;
    issuer?: string | undefined;
    jwtid?: string | undefined;
    mutatePayload?: boolean | undefined;
    noTimestamp?: boolean | undefined;
    header?: JwtHeader | undefined;
    encoding?: string | undefined;
    allowInsecureKeySizes?: boolean | undefined;
    allowInvalidAsymmetricKeyTypes?: boolean | undefined;
}

callback則是一個(gè)回調(diào)函數(shù)云稚,有兩個(gè)參數(shù),默認(rèn)返回Token

export type SignCallback = (
    error: Error | null,
    encoded: string | undefined,
) => void;

通過(guò)以上方法加密之后的結(jié)果就是一個(gè)Token

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjU3ZmVmMTY0ZTU0YWY2NGZmYzUzZGJkNSIsInhzcmYiOiI0ZWE1YzUwOGE2NTY2ZTc2MjQwNTQzZjhmZWIwNmZkNDU3Nzc3YmUzOTU0OWM0MDE2NDM2YWZkYTY1ZDIzMzBlIiwiaWF0IjoxNDc2NDI3OTMzfQ.PA3QjeyZSUh7H0GfE0vJaKW4LjKJuC3dVLQiY4hii8s

總結(jié)

在整個(gè)的Koa中沈堡,用到了jsonwebtoken這個(gè)依賴包静陈,里面有sign()方法

而我們前端所得到的數(shù)據(jù)通過(guò)sign()加密出來(lái)的包含自定義秘鑰的一份用戶信息而已

至于用戶信息中有什么內(nèi)容,可以隨便處理诞丽,比如用戶的ID鲸拥、用戶名、昵稱僧免、頭像等等

那么這個(gè)Token后續(xù)有什么用呢崩泡?

后續(xù)我們可以在前端的攔截器中配置這個(gè)Token,讓每一次的請(qǐng)求都攜帶這個(gè)Token猬膨,因?yàn)?code>Koa后續(xù)需要對(duì)每一次請(qǐng)求進(jìn)行Token的驗(yàn)證

比如登錄成功后請(qǐng)求用戶的信息,獲取動(dòng)態(tài)路由呛伴,再通過(guò)前端的router.addRoutes()將動(dòng)態(tài)路由添加到路由對(duì)象中去即可

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末勃痴,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子热康,更是在濱河造成了極大的恐慌沛申,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,941評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件姐军,死亡現(xiàn)場(chǎng)離奇詭異铁材,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)奕锌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門著觉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人惊暴,你說(shuō)我怎么就攤上這事饼丘。” “怎么了辽话?”我有些...
    開(kāi)封第一講書人閱讀 165,345評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵肄鸽,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我油啤,道長(zhǎng)典徘,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 58,851評(píng)論 1 295
  • 正文 為了忘掉前任益咬,我火速辦了婚禮逮诲,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己汛骂,他們只是感情好罕模,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著帘瞭,像睡著了一般淑掌。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蝶念,一...
    開(kāi)封第一講書人閱讀 51,688評(píng)論 1 305
  • 那天抛腕,我揣著相機(jī)與錄音,去河邊找鬼媒殉。 笑死担敌,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的廷蓉。 我是一名探鬼主播全封,決...
    沈念sama閱讀 40,414評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼桃犬!你這毒婦竟也來(lái)了刹悴?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 39,319評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤攒暇,失蹤者是張志新(化名)和其女友劉穎土匀,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體形用,經(jīng)...
    沈念sama閱讀 45,775評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡就轧,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了田度。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片妒御。...
    茶點(diǎn)故事閱讀 40,096評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖镇饺,靈堂內(nèi)的尸體忽然破棺而出携丁,到底是詐尸還是另有隱情,我是刑警寧澤兰怠,帶...
    沈念sama閱讀 35,789評(píng)論 5 346
  • 正文 年R本政府宣布梦鉴,位于F島的核電站,受9級(jí)特大地震影響揭保,放射性物質(zhì)發(fā)生泄漏肥橙。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評(píng)論 3 331
  • 文/蒙蒙 一秸侣、第九天 我趴在偏房一處隱蔽的房頂上張望存筏。 院中可真熱鬧宠互,春花似錦、人聲如沸椭坚。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,993評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)善茎。三九已至券册,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間垂涯,已是汗流浹背烁焙。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,107評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留耕赘,地道東北人骄蝇。 一個(gè)月前我還...
    沈念sama閱讀 48,308評(píng)論 3 372
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像操骡,于是被迫代替她去往敵國(guó)和親九火。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容