欢迎各位兄弟 发布技术文章

这里的技术是共享的

You are here

宁皓网 JWT:JSON Web Token

了解一下认证与授权用的一种 Token:JWT。

封面摄影:Timothy Poulton
 

介绍
1)JWT:JSON Web Token

用户提供他的用户名还有密码,我们收到请求以后,要验证一下,检查一下自己的数据库,看看能不能找到这个用户,密码匹不匹配 ... 如果验证通过了,我们就给这个用户签发一个 Token,中文可以翻译成令牌 ...

用户得到我们签发给他的这个 Token,可以找个地方存储起来,比如存储在浏览器的 Cookie 里面 .. 下回这个用户再向我们的应用请求一些特定资源的时候,需要提供这个 Token ...

我们得到这个 Token 以后,要检验一下这个 Token 对不对,看看是不是我们自己签发的 ... 检查通过以后,可以根据 Token 里面包含的数据,确定用户是谁,有什么权限 .. 然后可以决定是否要把用户请求的资源交给他 ...

这个 Token 的格式,生成,还有验证它用的方法,可以使用 jwt ,也就是 JSON Web Token ...

来自 https://ninghao.net/video/5020#info

2)JWT 的组成

这里左边显示的就是一个带签名的 jwt .. 它里面包含了三个部分 ..header ,头部,payload,具体的数据,最后还有一个签名 .. 整体看起来就是一大串字符 ...

注意,每个部分的中间都用了一个点分隔开 ... 这三个部分对应的内容是右边这些 .. 最上面这个是 header .. 就是 jwt 的头部, jwt 的头部就是描述一下这个 jwt 本身 ... 比如用的算法,还有类型 ... ,alg 表示 algorithm,就是算法,这个算法指的是 jwt 里的签名用的算法 .. typ 是 type 表示类型 ... 头部数据的格式是 JSON ... 这块数据要用 base64 这种方法去编码一下 ...

编码之后,还得做点特点的设置,比如去掉结尾的等号,把加号换成小横线,把斜线换成下划线 .. 完成以后,就是你在左边这里看到的第一部分内容 ...

数据里的字段,比如 alg,typ 这些东西,在 JWT 里叫 claims ..

下面这块是 Payload .. 这里包含的是 JWT 里的具体的数据 .. 这里有一些注册的 claim,比如这个 sub 表示的是 Subject,还有比如 iss,是 issuer,表示生成 JWT 的是谁,exp 是 expiration ,表示过期时间,jti 是 JWT ID ...

这些注册的 claim ,就是官方规定的一些名字,还有具体表示的意义 ... 你可以参考 jwt 官方文档去看看这些注册的 claim 都有哪些,意思是什么 ..

剩下的东西,我们可以自己随便往这个 payload 里面放 ... 比如 name 可能表示的是用户名 ... admin 表示用户是否是管理员 ...

你可以自己定义 claim 的名字,还有对应的值 ... 这块数据用 base64 编码以后,就是你在左边这里看到的这个 jwt 里的第二块内容 ...

最后一部分是一个签名 .. 签名要用一种 JWT 支持的算法去处理特定的数据 ... 这个要处理的数据包括 jwt 的用 base64 编码之后的 header,还有 payload ...

签名还要有一个密钥,这个密钥相当于是 JWT 的密码 .. 验证 JWT 的时候同样需要这个密钥 .. 有了这个密钥,你能知道 JWT 里的内容是否有人动过手脚 ...

我们验证了用户的身份以后,就给他签发一个 jwt,这个 jwt 里的内容可以用在前端应用上,比如 payload 里面包含的用户名 .. 你可以直接把它显示在前端 .. 不需要再到后端查询了 .. 再比如这个 admin ,表示用户是否是管理员 ... 用户访问后端一些资源的时候,可以直接使用 jwt 里的 admin 的值来确定用户是不是管理员 ..

我们可以相信 jwt 里的内容,因为它是我们自己签发给用户的 ... 用户如果自己解码了 jwt 里的内容,修改了里面的内容,重新生成了 jwt ..这个重新生成的 jwt 不能通过我们的验证 ... 因为用户不知道我们签发 jwt 的时候用的那个密钥 ...

来自 https://ninghao.net/video/5021#info

签发与验证
3)创建与签发 JWT

不同的语言都会提供一些库或者功能包去签发还有验证 JWT ... 下面我会用 Node.js 做一下演示 ...

这里我用到一个叫 jsonwebtoken 的 package .. 在项目里面可以先用 npm 或者 yarn 去安装一下这个包. . 打开命令行工具 ... 进入到我之前介绍 Node.js 的时候创建的这个项目 ..

yarn add jsonwebtoken

然后用编辑器打开我的这个 Node.js 项目 ..

打开这个 index.js ,先在这个文件里试一下去创建一个 JWT ..

我们只需要准备 Token 里的 payload,也就是数据 ... 不用担心 JWT 的 header,还有签名 ...

先在文件里导入 jsonwebtoken ,名字是 jwt ...

再准备一个 payload,就是 token 里的实际的数据 .. 一个对象 .. 添加一个 name 表示用户名 ... wanghao ... 再添加一个 admin ,表示是否是管理员 .. 设置成 true ...

签发的 token 还需要用到一个密钥 ... 添加一个 secret ... 值是 'ILOVENINGHAO' ... 验证 Token 的时候同样需要用到这个密钥...

然后用这个 payload,还有这个密钥去签发一个 token .. 用的是 sign 这个方法 ... jwt.sign .. 先把 payload 告诉它 ... 然后把签名用的密钥告诉这个方法 ...

这样我们就会得到一个 jwt ... 可以把结果输出到控制台上 ...

回到命令行 ... 进入到项目所在的目录 ... 执行一下 node index.js ...

这里输出的这串字符就是生成的 jwt ... 为用户签发了 jwt 以后,你可以把它交给用户 ... 下次他们再访问网站或者应用里的特定资源的时候,可以提供我们签发给它们的 jwt ...

复制一下这个 token 内容 ... jwt 的官方网站有个调试 jwt 的功能 ... 或者也可以安装一个调试 jwt 的浏览器插件 ...

把 token 粘贴过来 .. 会显示解码之后的 token 里的 header 还有 payload ..

不过提示签名无效 ... 这里我们要输入签发 token 的时候用的密钥 ... ILOVENINGHAO

这样就会显示 Signature Verified ... 签名验证通过了 ...

来自 https://ninghao.net/video/5023#info

4)验证与解码 JWT

用户访问需要验证身份的资源的时候,要提供我们签发给他的 token .. 拿到 token 以后我们要验证一下,看看这个 token 是不是我们自己验发的,如果验证通过,可以再根据 token 里的内容,来决定是不是要把用户访问的资源响应给他 ...

之前我们用 sign 方法签发了一个 token , 现在我们再用 verify 这个方法,可以验证一下这个 token ... 先把要验证的 token 告诉这个方法,然后再把签发 token 的时候用的密钥也告诉它 ...

这个方法有个回调 ... 里面有两个参数,error 表示错误,decoded 是解码之后的东西 .. 也就是 token 里面包含的具体的数据 ..

先判断一下,如果有 error ,就在控制台上输出 error 里的 message ... 再 return 一下 ..

没有的话,就表示验证成功,这样 decoded 里面就是 token 里的内容,我们可以再把它输出到控制台上看一下 ..

回到命令行 ... 执行一下 node index.js ..

这里会输出解码之后的 token 里的内容 ... 这里除了我们签发 token 的时候放进去的 name 还有 admin ,这里还有一个 iat ,这个 claim 是 issued at ,表示签发这个 token 的时候的时间 ..

如果有不怀好意的用户想要篡改我们签发的 token ... 只要他不知道我们签发 token 的时候用的密钥,他就没有办法伪造我们的 token ..

可以试一下 ... 比如在验证的时候,修改一下使用的 secret ..

回到命令行,再执行一下 node index.js ..

这次会提示 invalid signature ... 无效的签名 ...

我们可以再把验证用的密钥修改成原来的 secret ...

来自 https://ninghao.net/video/5024#info

RS256
5)用 RS256 算法签发 JWT

默认 JWT 的签名算法用的是 HS256 .. 这种算法在签名还有验证的时候用的是同一个密码 .. 这种叫对称算法 .. 我们也可以用 RS256 这种算法 .. 它是一种非对称算法 ... 在签名的时候使用它要用到一个私钥 ... 就是一个 Private Key ... 在验证的时候需要用到公钥 ... 就是 Public Key ..

使用这种算法,你可以在一个单独的地方,用私钥签发 JWT ... 在其它的地方,可以使用公钥去验证我们签发的 JWT ... 也就是有私钥的地方才能签发 JWT .. 没有私钥,但是有公钥的地方只能去验证 jwt,不能签发 jwt ..

现在我们可以使用 openssl 去生成一个私钥,再根据这个私钥去生成一个公钥 ... 打开命令行工具 ... Windows 上可以使用 cmder ,你可以新建一个 cmd 类型的界面,或者 bash 类型的界面 ... mac 用户可以用系统自带的终端 ...

先去生成一个私钥 .. 进入到想要保存私钥文件的地方 ... 创建一个目录,名字是 config,再进入到 config 目录的下面 .. 然后执行一下 ..

ssh-keygen -t rsa -b 2048 -f private.key

再根据这个私钥生成一个公钥 ..

openssl rsa -in private.key -pubout -outform PEM -out public.key

查看一下 .. 这里这个 private.key.pub 文件没什么用,可以把它删除掉 ...

现在我们这里两个文件 ... private.key ,私钥,还有一个 public.key,公钥 .. 我们先根据这个私钥去签发一个 jwt ..

打开 index.js ... 先添加一段注释 ... 说明一下默认用的是 HS256 这种算法 ... 然后把签发还有验证 jwt 的代码注释掉 ..

再添加一段注释 ... 下面用一下 RS256 这种算法 ... 我们可以把私钥文件里的内容读取过来 ... 需要用到 Node.js 的 fs 模块 ... 先在文件的顶部导入这个模块 .. 名字是 fs ...

添加一个 privateKey ,表示私钥 ... 用一下 fs 的 readFileSync 方法,它是读取文件里内容的同步方法 .. 文件的位置是 ./config/private.key

再签发一个 token ... 用一下 jwt 的 sign 方法, token 的数据是 payload .. 这个签名算法要用一下 privateKey,就是之前我们生成的私钥文件里的内容 ..

然后是个对象 ... 里面添加一个 algorithm ... 用这个选项指定一下签名用的算法,默认它的值是 HS256 ,这里我们要设置成 RS256 ..

最后在控制台上输出签发的这个 token 里的内容 ...

回到命令行, 回到上一级目录 .. 执行一下 node index.js

... 会得到签发的这个 token ... 复制一下 ...

再打开 jwt 的调试工具 ... 把 token 内容先粘贴上去 .. 右边会显示解码之后的内容 ... 注意这个 token 的 header 里面,有个 alg ,它的值是 RS256,它表示的是这个 token 用的算法 ..

上面的算法选择 RS256 ... 然后再打开 public key ,就是公钥这个文件,复制一下里面的内容 ... 粘贴到调试工具里面 ..

这样就会提示 Signature Verified ,签名验证成功 ...

来自  https://ninghao.net/video/5026#info

6)用 RS256 算法验证 JWT
再去验证一下用 RS256 算法签发的这个 JWT .. 验证要用到公钥内容 ... 可以先添加一个 publicKey ,用一下 fs 的 readFileSync 读一下 ./config/public.key 这个文件里的东西 ..

验证用的是 jsonwebtoken 的 verify 方法 .. 先把要验证的 token 交给它 ... 这个 token 是用 RS256 算法签发的,所以验证的时候,我们要用到对应的公钥 ..

一个回调 ... 有个 error 参数,里面会包含验证失败的错误 .. 还有一个 decoded ,解码以后的 token 里的内容会在这个 decoded 里找到 ..

有错误 ... 就把 error 里的 message 输出到控制台上 ... 再 return 一下 ..

验证成功 ... 我们就把 decoded 输出到控制台上 ....

回到命令行 ... 执行一下 node index.js ...

这里会显示验证成功以后,解码之后的 token 里面包含的数据 ...

来自 https://ninghao.net/video/5027#info

普通分类: