jwt

一.前沿

jwt是json web token縮寫。它將用戶信息加密到token里,服務(wù)器不保存任何用戶信息,服務(wù)器通過保存的密鑰驗(yàn)證token的正確性,只要正確即通過驗(yàn)證。
優(yōu)點(diǎn)是在分布式系統(tǒng)中,很好地解決了單點(diǎn)登錄問題,很容易解決了session共享的問題。比如一個(gè)公司有很多相關(guān)聯(lián)的網(wǎng)站,比如A,B,C。通常希望用戶在登陸A網(wǎng)站以后,再訪問B,C網(wǎng)站能夠自動(dòng)登錄(也就是所謂的單點(diǎn)登陸)。
缺點(diǎn)是無法作廢已頒布的令牌/不易應(yīng)對數(shù)據(jù)過期。比如說,我登陸了A網(wǎng)站,再登錄B網(wǎng)站,在token過期之前,token始終是有效的,無法廢除token的有效性。

二.jwt原理

JWT的原理是服務(wù)器認(rèn)證以后,生成一個(gè)下面所示的對象,發(fā)送給用戶。

{
 name:hello,
 roles: 管理員,
 expires:2018年11月
}

以后,用戶與服務(wù)端通信的時(shí)候,都要發(fā)回這個(gè) JSON 對象。服務(wù)器完全只靠這個(gè)對象認(rèn)定用戶身份。當(dāng)然,出于安全的考慮,服務(wù)器不能發(fā)送明文的數(shù)據(jù)給用戶,通常需要對這個(gè)對象進(jìn)行加密。

三.jwt加密生成token

這里使用了jsonwebtoken來生成token
jwt.sign(payload, secretOrPrivateKey, [options, callback])
1.Payload 部分是一個(gè) JSON 對象,用來存放實(shí)際需要傳遞的數(shù)據(jù).比如:

{
  id:user.id,
  name:user.name
}

2.secretOrPrivateKey:是加密的名字,可以自己定義
3.第三個(gè)參數(shù)是可選的,主要包括加密方式,過期時(shí)間等,一般只需要設(shè)置過期時(shí)間expiresIn,加密方式默認(rèn)使用HS256

                  const rule = {id:user.id,name:user.name};
                  jwt.sign(rule,keys.secretOrKey,{expiresIn:3600},(err,token) => {
                    if(err) throw err;
                    res.json({
                      success:true,
                      token:"Bearer " + token
                    });
                  })

token組成

最終生成的token如下圖所示:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJuYW1lIjoiaGVsbG8iLCJpYXQiOjE1NDMzOTUyMDgsImV4cCI6MTU0MzM5ODgwOH0.
zFiGRNTST8RSY3e1JqWx0SA0S4BCOgNCVsUC4u9JHbY

可以觀察到生成的token被 .劃分開來,由三部分組成。這三部分分別是Header,
Payload,Signature
。其中:
Header是一個(gè)對象,描述 JWT 的元數(shù)據(jù),通常是下面的樣子。

{
  "alg": "HS256",
  "typ": "JWT"
}

上面代碼中,alg屬性表示簽名的算法(algorithm),默認(rèn)是 HMAC SHA256(寫成 HS256);typ屬性表示這個(gè)令牌(token)的類型(type),JWT 令牌統(tǒng)一寫為JWT。最后將上面的 JSON 對象使用 Base64URL 算法轉(zhuǎn)成字符串,也就是token的第一部分。

Payload也是一個(gè)對象,就是我們上面提到的需要傳遞的數(shù)據(jù)組成的對象

Signature 部分是對前兩部分的簽名,防止數(shù)據(jù)篡改。

首先,需要指定一個(gè)密鑰(secret)。這個(gè)密鑰只有服務(wù)器才知道,不能泄露給用戶。然后,使用 Header 里面指定的簽名算法(默認(rèn)是 HMAC SHA256),按照下面的公式產(chǎn)生簽名。

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

四.使用passport驗(yàn)證token(passport-jwt驗(yàn)證jwt類型的token)

passport通常是用來實(shí)現(xiàn)登陸驗(yàn)證。這里我們使用passport-jwt來進(jìn)行驗(yàn)證jwt類型的token。
1.使用passport
app.js

const passport = require('passport');
app.use(passport.initialize());

const JwtStrategy = require('passport-jwt').Strategy,
  ExtractJwt = require('passport-jwt').ExtractJwt;
const opts = {}

//得到token
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();
//設(shè)置token時(shí)使用的加密名字
opts.secretOrKey = 'secret';

passport.use(new JwtStrategy(opts, function(jwt_payload, done) {
  console.log(jwt_payload);
}));

1. JwtStrategy用來定義策列,是在路由執(zhí)行之前執(zhí)行。
2. ExtractJwt里面包含很多函數(shù),這里需要注意的是fromAuthHeaderAsBearerToken**是獲取到請求時(shí)以Bearer +token得到的token。
注意:他只能獲取到以Bearer+一個(gè)空格開頭的token。因此我們這里的token必須以Bearer+ 一個(gè)空格開頭。如下所示:

res.json(
{
   success:true,
   token:"Bearer "+token
})

3.opts對象里面定義的各個(gè)參數(shù)是我們之前創(chuàng)建token設(shè)置的參數(shù)
opts.jwtFromRequest:用于從request中獲取token
opts.secretOrKey:是之前設(shè)置的加密名字

4.passport.use(new JwtStrategy(opts, function(jwt_payload, done) {}))使用passport.use()定義策略。
回調(diào)函數(shù)中的jwt_payload時(shí)一個(gè)包含id,name等的對象。

{ name: 'hello', id: 'hello', iat: 1543401227, exp: 1543404827 }

根據(jù)payload中的id,我們可以查詢是否有這個(gè)對象。
回調(diào)函數(shù)的第二個(gè)參數(shù)done是一個(gè)函數(shù)(相當(dāng)于next),這個(gè)函數(shù)第一個(gè)參數(shù)是err,第二個(gè)參數(shù)是user。我們可以通過done將user進(jìn)行返回,這樣的話在請求中就把user對象添加進(jìn)去了。如下所示:

 passport.use(new JwtStrategy(opts, function(jwt_payload, done) {
    // console.log(jwt_payload);
    User.findById(jwt_payload.id)
      .then((user) => {
        if(user){
          return done(null,user)
        }else{
          return done(null,false);
        }
      })
  }));

user.js
這樣的話,在其他任何進(jìn)行路由的地方都可以使用passport.authenticate進(jìn)行驗(yàn)證.

router.get('/current',passport.authenticate('jwt',{ session: false }),(req,res) => {
  console.log(req.user);  //{ name: 'hello', id: 'hello', iat: 1543401227, exp: 1543404827 }
});

注意:非常重要的一點(diǎn)就是我們?nèi)绻褂昧藀assport進(jìn)行了驗(yàn)證。那么就可以從請求中獲取到user,當(dāng)然前提是調(diào)用了done函數(shù),返回了user。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 一、什么是JWT JWT(JSON Web Token) 是一個(gè)開放標(biāo)準(zhǔn)(RFC 7519),它定義了一種緊湊的、...
    AaronSimon閱讀 20,230評論 2 10
  • tips:接下去會(huì)在github寫博客,簡書不再更新和修改文章,歡迎大家逛逛我的新博客點(diǎn)擊查看 ,我會(huì)盡量用更容易...
    aermin閱讀 5,674評論 0 10
  • 原文地址 JWT 是什么,為何要使用 JWT? JWT 是 JSON Web Tokens 的簡稱,對于這個(gè)問題最...
    DAI_WEI閱讀 7,771評論 2 7
  • 自3月底加入小灶群之后,收獲出乎我的意料。當(dāng)時(shí)的我處于產(chǎn)后輕微的抑郁,首先得感謝小灶群給我?guī)淼姆e極向上的能量。 ...
    shmily由由and花花閱讀 284評論 0 2
  • 文/書~范乘風(fēng) 明月入禪心,長伴青燈向此身。 莫道淡茶皆寡味,癡嗔。 半入清風(fēng)半留溫。 古卷抵千金,字里行間醒世人...
    范乘風(fēng)閱讀 730評論 0 5

友情鏈接更多精彩內(nèi)容