jwt

一.前沿

jwt是json web token缩写。它将用户信息加密到token里,服务器不保存任何用户信息,服务器通过保存的密钥验证token的正确性,只要正确即通过验证。
优点是在分布式系统中,很好地解决了单点登录问题,很容易解决了session共享的问题。比如一个公司有很多相关联的网站,比如A,B,C。通常希望用户在登陆A网站以后,再访问B,C网站能够自动登录(也就是所谓的单点登陆)。
缺点是无法作废已颁布的令牌/不易应对数据过期。比如说,我登陆了A网站,再登录B网站,在token过期之前,token始终是有效的,无法废除token的有效性。

二.jwt原理

JWT的原理是服务器认证以后,生成一个下面所示的对象,发送给用户。

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

以后,用户与服务端通信的时候,都要发回这个 JSON 对象。服务器完全只靠这个对象认定用户身份。当然,出于安全的考虑,服务器不能发送明文的数据给用户,通常需要对这个对象进行加密。

三.jwt加密生成token

这里使用了jsonwebtoken来生成token
jwt.sign(payload, secretOrPrivateKey, [options, callback])
1.Payload 部分是一个 JSON 对象,用来存放实际需要传递的数据.比如:

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

2.secretOrPrivateKey:是加密的名字,可以自己定义
3.第三个参数是可选的,主要包括加密方式,过期时间等,一般只需要设置过期时间expiresIn,加密方式默认使用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是一个对象,描述 JWT 的元数据,通常是下面的样子。

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

上面代码中,alg属性表示签名的算法(algorithm),默认是 HMAC SHA256(写成 HS256);typ属性表示这个令牌(token)的类型(type),JWT 令牌统一写为JWT。最后将上面的 JSON 对象使用 Base64URL 算法转成字符串,也就是token的第一部分

Payload也是一个对象,就是我们上面提到的需要传递的数据组成的对象

Signature 部分是对前两部分的签名,防止数据篡改。

首先,需要指定一个密钥(secret)。这个密钥只有服务器才知道,不能泄露给用户。然后,使用 Header 里面指定的签名算法(默认是 HMAC SHA256),按照下面的公式产生签名。

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

四.使用passport验证token(passport-jwt验证jwt类型的token)

passport通常是用来实现登陆验证。这里我们使用passport-jwt来进行验证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();
//设置token时使用的加密名字
opts.secretOrKey = 'secret';

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

1. JwtStrategy用来定义策列,是在路由执行之前执行。
2. ExtractJwt里面包含很多函数,这里需要注意的是fromAuthHeaderAsBearerToken**是获取到请求时以Bearer +token得到的token。
注意:他只能获取到以Bearer+一个空格开头的token。因此我们这里的token必须以Bearer+ 一个空格开头。如下所示:

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

3.opts对象里面定义的各个参数是我们之前创建token设置的参数
opts.jwtFromRequest:用于从request中获取token
opts.secretOrKey:是之前设置的加密名字

4.passport.use(new JwtStrategy(opts, function(jwt_payload, done) {}))使用passport.use()定义策略。
回调函数中的jwt_payload时一个包含id,name等的对象。

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

根据payload中的id,我们可以查询是否有这个对象。
回调函数的第二个参数done是一个函数(相当于next),这个函数第一个参数是err,第二个参数是user。我们可以通过done将user进行返回,这样的话在请求中就把user对象添加进去了。如下所示:

 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
这样的话,在其他任何进行路由的地方都可以使用passport.authenticate进行验证.

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

注意:非常重要的一点就是我们如果使用了passport进行了验证。那么就可以从请求中获取到user,当然前提是调用了done函数,返回了user。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,406评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,732评论 3 393
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,711评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,380评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,432评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,301评论 1 301
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,145评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,008评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,443评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,649评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,795评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,501评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,119评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,731评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,865评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,899评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,724评论 2 354

推荐阅读更多精彩内容

  • 一、什么是JWT JWT(JSON Web Token) 是一个开放标准(RFC 7519),它定义了一种紧凑的、...
    AaronSimon阅读 19,905评论 2 10
  • tips:接下去会在github写博客,简书不再更新和修改文章,欢迎大家逛逛我的新博客点击查看 ,我会尽量用更容易...
    aermin阅读 5,562评论 0 10
  • 原文地址 JWT 是什么,为何要使用 JWT? JWT 是 JSON Web Tokens 的简称,对于这个问题最...
    DAI_WEI阅读 7,648评论 2 7
  • 自3月底加入小灶群之后,收获出乎我的意料。当时的我处于产后轻微的抑郁,首先得感谢小灶群给我带来的积极向上的能量。 ...
    shmily由由and花花阅读 236评论 0 2
  • 文/书~范乘风 明月入禅心,长伴青灯向此身。 莫道淡茶皆寡味,痴嗔。 半入清风半留温。 古卷抵千金,字里行间醒世人...
    范乘风阅读 671评论 0 5