基于 Token 的身份验证:JSON Web Token(JWT)

转自:https://ninghao.net/blog/2834

1、传统身份验证和JWT的身份验证

传统身份验证:

      HTTP 是一种没有状态的协议,也就是它并不知道是谁是访问应用。这里我们把用户看成是客户端,客户端使用用户名还有密码通过了身份验证,不过下回这个客户端再发送请求时候,还得再验证一下。
    解决的方法就是,当用户请求登录的时候,如果没有问题,我们在服务端生成一条记录,这个记录里可以说明一下登录的用户是谁,然后把这条记录的 ID 号发送给客户端,客户端收到以后把这个 ID 号存储在 Cookie 里,下次这个用户再向服务端发送请求的时候,可以带着这个 Cookie ,这样服务端会验证一个这个 Cookie 里的信息,看看能不能在服务端这里找到对应的记录,如果可以,说明用户已经通过了身份验证,就把用户请求的数据返回给客户端。
    上面说的就是 Session,我们需要在服务端存储为登录的用户生成的 Session ,这些 Session 可能会存储在内存,磁盘,或者数据库里。我们可能需要在服务端定期的去清理过期的 Session 。

JWT的身份验证:

使用基于 Token 的身份验证方法,在服务端不需要存储用户的登录记录。大概的流程是这样的:
1、客户端使用用户名跟密码请求登录
2、 服务端收到请求,去验证用户名与密码
3、验证成功后,服务端会签发一个 Token,再把这个 Token 发送给客户端
4、客户端收到 Token 以后可以把它存储起来,比如放在 Cookie 里或者 Local Storage 里
5、客户端每次向服务端请求资源的时候需要带着服务端签发的 Token
6、服务端收到请求,然后去验证客户端请求里面带着的 Token,如果验证成功,就向客户端返回请求的数据

2、JWT的token组成

    实施 Token 验证的方法挺多的,还有一些标准方法,比如 JWT,读作:jot ,表示:JSON Web Tokens 。JWT 标准的 Token 有三个部分:
    header(头部)
    payload(数据)
    signature(签名)
    中间用点分隔开,并且都会使用 Base64 编码,所以真正的 Token 看起来像这样:

eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJuaW5naGFvLm5ldCIsImV4cCI6IjE0Mzg5NTU0NDUiLCJuYW1lIjoid2FuZ2hhbyIsImFkbWluIjp0cnVlfQ.SwyHTEx_RQppr97g4J5lKXtabJecpejuef8AqKYMAJc

头部:

每个 JWT token 里面都有一个 header,也就是头部数据。里面包含了使用的算法,这个 JWT 是不是带签名的或者加密的。主要就是说明一下怎么处理这个 JWT token 。

头部里包含的东西可能会根据 JWT 的类型有所变化,比如一个加密的 JWT 里面要包含使用的加密的算法。唯一在头部里面要包含的是 alg 这个属性,如果是加密的 JWT,这个属性的值就是使用的签名或者解密用的算法。如果是未加密的 JWT,这个属性的值要设置成 none

示例:


1.png

意思是这个 JWT 用的算法是 HS256。上面的内容得用 base64url 的形式编码一下,所以就变成这样:

2.png

Payload:

Payload 里面是 Token 的具体内容,这些内容里面有一些是标准字段,你也可以添加其它需要的内容。下面是标准字段:

iss:Issuer,发行者
sub:Subject,主题
aud:Audience,观众
exp:Expiration time,过期时间
nbf:Not before
iat:Issued at,发行时间
jti:JWT ID
比如下面这个 Payload ,用到了 iss 发行人,还有 exp 过期时间这两个标准字段。另外还有两个自定义的字段,一个是 name ,还有一个是 admin 。


3.png

使用 base64url 编码以后就变成了这个样子:


4.png

Signature:

JWT 的最后一部分是 Signature ,这部分内容有三个部分,先是用 Base64 编码的 header.payload ,再用加密算法加密一下,加密的时候要放进去一个 Secret ,这个相当于是一个密码,这个密码秘密地存储在服务端。

header
payload
secret


5.png

处理完成以后看起来像这样:


6.png

最后这个在服务端生成并且要发送给客户端的 Token 看起来像这样:
7.png

客户端收到这个 Token 以后把它存储下来,下回向服务端发送请求的时候就带着这个 Token 。服务端收到这个 Token ,然后进行验证,通过以后就会返回给客户端想要的资源。

3、签发和验证JWT的功能

在应用里实施使用基于 JWT 这种 Token 的身份验证方法,你可以先去找一个签发与验证 JWT 的功能包。无论你的后端应用使用的是什么样的程序语言,系统,或者框架,你应该都可以找到提供类似功能的包。
下面我们在一个 Node.js 项目里,用最简单的方式来演示一下签发还有验证 JWT 的方法。练习有个视频版本,你可以参考《 JWT:JSON Web Token 》这个免费的视频课程。

项目代码https://github.com/ninghao/jwt-demo

准备项目

准备一个简单的 Node.js 项目:
下面我们在一个 Node.js 项目里,用最简单的方式来演示一下签发还有验证 JWT 的方法。练习有个视频版本,你可以参考《 JWT:JSON Web Token 》这个免费的视频课程。

项目代码https://github.com/ninghao/jwt-demo

准备项目

准备一个简单的 Node.js 项目:

8.png

安装签发与验证 JWT 的功能包,我用的叫 jsonwebtoken,在项目里安装一下这个包:
9.png

签发 JWT

在项目里随便添加一个 .js 文件,比如 index.js,在文件里添加下面这些代码:


10.png

非常简单,就是用了刚刚为项目安装的 jsonwebtoken 里面提供的 jwt.sign 功能,去签发一个 token。这个 sign 方法需要三个参数:

playload:签发的 token 里面要包含的一些数据。
secret:签发 token 用的密钥,在验证 token 的时候同样需要用到这个密钥。
options:一些其它的选项。
在命令行下面,用 node 命令,执行一下项目里的 index.js 这个文件(node index.js),会输出应用签发的 token:


11.png

上面的 Token 内容并没有加密,所以如果用一些 JWT 解码功能,可以看到 Token 里面包含的内容,内容由三个部分组成,像这样:


12.png

假设用户通过了某种身份验证,你就可以使用上面的签发 Token 的功能为用户签发一个 Token。一般在客户端那里会把它保存在 Cookie 或 LocalStorage 里面。

用户下次向我们的应用请求受保护的资源的时候,可以在请求里带着我们给它签发的这个 Token,后端应用收到请求,检查签名,如果验证通过确定这个 Token 是我们自己签发的,那就可以为用户响应回他需要的资源。

验证 JWT

验证 JWT 的用效性,确定一下用户的 JWT 是我们自己签发的,首先要得到用户的这个 JWT Token,然后用 jwt.verify 这个方法去做一下验证。这个方法是 Node.js 的 jsonwebtoken 这个包里提供的,在其它的应用框架或者系统里,你可能会找到类似的方法来验证 JWT。

打开项目的 index.js 文件,里面添加几行代码:


13.png

把要验证的 Token 数据,还有签发这个 Token 的时候用的那个密钥告诉 verify 这个方法,在一个回调里面有两个参数,error 表示错误,decoded 是解码之后的 Token 数据。

执行:


14.png

输出:


15.png

注意输出了一个 invalid signature ,表示 Token 里的签名不对,这是因为我们组长 verify 方法提供的密钥并不是签发 Token 的时候用的那个密钥。这样修改一下:
16.png

再次运行,会输出类似的数据:


17.png

RS256 算法

默认签发还有验证 Token 的时候用的是 HS256 算法,这种算法需要一个密钥(密码)。我们还可以使用 RS256 算法签发与验证 JWT。这种方法可以让我们分离开签发与验证,签发时需要用一个密钥,验证时使用公钥,也就是有公钥的地方只能做验证,但不能签发 JWT。

在项目下面创建一个新的目录,里面可以存储即将生成的密钥与公钥文件。


18.png

密钥

先生成一个密钥文件:


19.png

公钥

基于上面生成的密钥,再去创建一个对应的公钥:


20.png

签发 JWT(RS256 算法)

用 RS256 算法签发 JWT 的时候,需要从文件系统上读取创建的密钥文件里的内容。


21.png

签发仍然使用 jwt.sign 方法,只不过在选项参数里特别说明一下使用的算法是 RS256:


22.png

验证 JWT(RS256 算法)

验证使用 RS256 算法签发的 JWT,需要在文件系统上读取公钥文件里的内容。然后用 jwt 的 verify 方法去做验证。


23.png

相关课程

  1. JWT:JSON Web Token
  2. Node.js:基于 Token 的身份验证
  3. WordPress 开发:身份验证(JWT)》
  4. 微信小程序:应用后台__身份验证 #3

感谢原创,如有侵权,可联系本人删除。

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

推荐阅读更多精彩内容