JWT验证
理解 JSON Web Token(JWT) 验证
JSON Web Token认证的操作指南

在本文中,我们将了解JSON Web Token的全部内容。
我们将从JWT的基本概念开始,然后查看其结构,最后创建一个简单的服务器,它将获取一些数据并将其插入到JWT中。
什么是JSON Web Token?为什么我们需要它?
JSON Web Token(JWT)是一种安全,紧凑且独立的方式,以JSON对象的形式在多方之间传输信息。
假设你想登录一个应用程序,比如说 Tinder。 Tinder允许用户使用他们的Facebook个人资料登录。 因此,当用户选择使用Facebook登录的选项时,该应用程序会使用用户的凭据(用户名和密码)联系Facebook的身份验证服务器。
验证服务器验证用户的凭据后,将创建JWT并将其发送给用户。 该应用程序现在获得此JWT并允许用户访问其数据。
jwt的结构
一个jwt是由三个以"."来区分开的部分来组成的,他们是:
- 头部
- 负载
- 签名
标头通常由两部分组成:令牌的类型和正在使用的散列算法。
{
"alg": "HS256",
"typ": "JWT"
}
负载是我们要发送的实际信息的存储位置。 以下是简单有效负载的示例。 要知道负载可能比这个示例更复杂,以确保更好的安全性。
{
"sub": "65165751325",
"name": "Rajat S",
"admin": true
}
签名用于验证消息在到达目的地之前没有被更改。 这通常通过使用私钥来实现。
这三个部分通常编码为三个在他们之间由.分隔的Base64-URI字符串
要轻松解码,验证,生成或只是使用JWT,请查看Auth0的JWT.IO调试器。
现在我们已经基本了解了JSON是什么,让我们来看看如何构建一个简单的身份验证服务器来发布JWT,然后我们将使用它来访问API。
提示:在JavaScript中编写可重用代码时,可以使用Bit快速将其转换为共享组件,以便在不同位置使用,开发和同步。 试试吧。
让我们开始吧
在开始之前, 让我们构建一个简单的web服务端,首先用npm下载express到你的电脑当中,然后打开命令行工具,执行以下语句
$ npm install express
然后,新建一个文件夹叫做 jwt-auth. 当然你也可以命名为其他名字
$ mkdir jwt-auth
$ cd jwt-auth
在这个文件夹里新建一个文件叫做index.js . 这个文件是用来写我们的代码并且启动一个web服务器,并且包含一个独立的路由能够显示当前日期和时间还有一个404页面的处理程序,
打开一个编辑器,写如下的代码
const express = require("express");
const app = express();
const PORT = 8888;
app.get('/time', (req, res) => {
const time = (new Date()).toLocaleTimeString();
res.status(200).send(`The Time is ${time}`);
});
在这里,我们首先导入我们刚刚安装的express库。 然后我正在创建一个名为app的const,它将使express库。 我还创建了另一个名为PORT的常量,它将包含我们的服务器将运行的端口号。 我选择了8888作为端口号。 如果您愿意,也可以使用任何其他端口号。
接下来,我创建了一个名为time的新路由。 此路由以响应和请求作为参数进行回调。 简而言之,此路由将向用户显示当前本地时间。
当想要服务器把我们带到除了time之外的任何路由时,我们还要添加一个路由。 这被称为catchall路由。 我希望服务器在此路由上返回404错误。 要实现此功能,请将以下代码写入index.js文件:
app.get("*", (req, res) => {
res.sendStatus(404);
});
还有最后一件事要做。 我们没有告诉我们的服务器要监听哪个端口。 我们已将端口号初始化为8888.但我们还没有在代码中实际使用此定义。 为此,请使用app.listen方法,如下所示:
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}.`);
});
完成后,我们可以通过命令行输入node来启动服务器。 然后,转到localhost:8888,您会发现它显示Not Found消息。 添加/时间到URL,它会显示本地时间,如下所示:

最终我们已经建立了一个express服务器,它将向我们在/time路由显示当地时间以及任何其他路由上的404错误。
**添加一个登陆路由
由于本文是关于JWT身份验证的,因此我们实现一个名为login的路由。 与之前使用get和listen的部分中的路由不同,此路由将使用post创建。
app.post("/login", (req, res) => {
const user = req.body.username;
res.status(200).send(`User's name is ${user}`);
})
但目前我们的服务器无法读取请求的正文。 为了解决这个问题,我们将安装一个名为body-parser的新中间件。
$ npm install body-parser
然后就像我们使用express库一样,使用require语法将其导入index.js文件。
const bodyParser = require("body-parser");
我们现在可以告诉express使用body-parser来处理所有JSON响应,如下所示:
app.use(bodyParser.json());
现在我们通过node.来启动服务器
为了测试这个新的路由,我们需要用到
,如果你还没有安装的话,下载一下这个吧。
在POSTMAN中,我们创建一个post请求到这个登陆路由,如下所示:

在这个请求体内,创建一个如下的json:

点击发送应该得到以下响应:

发布JWT
现在我们已经构建了一个可以处理GET和POST请求的简单服务器,让我们构建一个简单的JWT发布。
让我们首先创建一个名为users的新数组,其中包含几个用户及其密码,如下所示:
const users = [
{id: 1, username: "clarkKent", password: "superman"},
{id: 2, username: "bruceWayne", password: "batman"}
];
让我们重写 login 路由,首先我们需要检查提交上来的请求里面是否同时包含username 和 password,如果不是的话,那么服务端需要返回400状态码。
app.post("/login", (req, res) => {
if (!req.body.username || !req.body.password) {
res.status(400).send("Error. Please enter the correct username and password");
return;
}
然后如果这个请求有效,我们需要检查是否用户名在我们的users数组里面,
在if语句下面的相同的login路由中写:
const user = users.find((u) => {
return u.username === req.body.username && u.password === req.body.password;
});
如果这个用户并未在我们的users数组当中,我们需要返回401的状态码,同样是在/login路由中:
在继续进行之前,我们下载另一个库叫做 jsonwebtoken
$ npm install jsonwebtoken
在index.js文件的头部,用require语句引入jsonwebtoken,
const jwt = require("jsonwebtoken");
我们将使用此库为每个有效用户创建JSON Web令牌。 为此,我们将使用jsonwebtoken库中的sign方法创建一个名为token的新const。 请注意,我们仍然在/ login路由中编写代码。
const token = jwt.sign({
sub: user.id,
username: user.username
}, "mykey", {expiresIn: "3 hours"});
res.status(200).send({access_token: token})
现在去到POSTMAN,发送一个post请求,请求中带有如下的json结构
{
"username": "clarkKent",
"password": "superman",
}
运行结果会是如下的一个JSON Web Token

如果你复制这个access_token到 JWT.IO Debugger中,你会看到相同的用户名和密码,只不过多了一些其他的消息,

旁注 - CORS
在某些情况下,您的应用尝试访问的API运行在与应用程序不同的服务器上,将返回某种“无法加载”错误。
为了防止这种情况发生,我们可以安装另一个名为cors的库
$ npm install cors
在index.js头部,用require语句引入这个库
const cors = require("cors");
然后类似于我们对body-parser库所做的,我们将告诉express使用cors,如下所示:
app.use(cors());
使用JWT为API提供用户访问权限
在这里,我们将创建一个包含两个路由的新API。 第一个路由将是公共的,而第二个将要求用户使用JWT进行身份验证以便访问它。
让我们在jwt-auth文件夹中创建一个名为api.js的新文件。 在此文件中,编写以下启动代码:
const express = require("express");
const bodyParser = require("body-parser");
const app = express();
const PORT = process.env.API_PORT || 8888;
app.use(bodyParser.json());
app.get("*", (req, res) => {
res.sendStatus(404);
});
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}.`);
});
让我们创建一个路由名叫 '/asset' 这个是公共路由,将会直接返回一个200的状态码
app.get("/asset", (req, res) => {
res.status(200).send("Everybody can see this");
});
第二个秘密路由是/asset/secret,它将使用jwtCheck进行保护,如下所示:
app.get("/asset/secret", jwtCheck, (req, res) => {
res.status(200).send("Only logged in people can see me");
});
因为index.js文件已经设置启动在8888端口,我们需要把这个文件设置在其他端口,为了实现,我们需要打开命令行工具,然后运行如下代码:
$ export API_PORT=5555
尽管我们已经说过/ asset / secret路由是安全的,但我们还没有真正实现它。 为此,我们需要安装另一个名为express-jwt的中间件库。
$ npm install express-jwt
在index.js头部,用require语句引入这个库
const expressjwt = require("express-jwt");
我们将使用此库来定义jwtCheck。 我们将使用jwtCheck来检查签名是否与我们从身份验证服务器获得的签名相匹配。 如果你还记得,我们把它命名为“mykey”。
const jwtCheck = expressjwt({
secret: "mykey"
});
运行node api.js命令, 检查这个权限的运行情况是否正常, 去POSTMAN发送get请求到localhost:5000/asset,他的响应应该是Everybody can see this
然后你发送请求到localhost:5000/asset/secret ,你应该会看到一个大的错误提示:

要解决此问题,请转到POSTMAN中的Authentication选项卡,然后选择Type as Bearer Token。 然后输入Token的值为我们在前面部分中算出的值。
结论
与其他Web令牌(如简单Web令牌(SWT)或安全断言标记语言(SAML))相比,JWT更简单,因为它基于JSON,比XML更容易理解。
如果我们对JSON进行编码,它的大小将比SAML更小,从而更容易传入HTML和HTTP环境。
安全方面,SWT使用单个密钥,而JWT和SAML都使用公钥和私钥对进行更好的身份验证。
从使用的角度来看,JWT用于互联网规模。这意味着在用户的设备上处理更容易,无论是笔记本电脑还是移动设备。
除了身份验证之外,JSON Web令牌是一种在多方之间传输数据的绝佳方式。 JWT具有签名这一事实使每个人都可以更轻松地识别信息发送者。您只需要正确的密钥即可
JWT验证的更多相关文章
- 踩坑之路---JWT验证
使用JWT验证客户的携带的token 客户端在请求接口时,需要在request的head中携带一个token令牌 服务器拿到这个token解析获取用户资源,这里的资源是非重要的用户信息 目前我的理解, ...
- golang学习笔记10 beego api 用jwt验证auth2 token 获取解码信息
golang学习笔记10 beego api 用jwt验证auth2 token 获取解码信息 Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放 ...
- springboot成神之——basic auth和JWT验证结合
本文介绍basic auth和JWT验证结合 目录结构 依赖 config配置文件WebSecurityConfig filter过滤器JWTLoginFilter filter过滤器JWTAuthe ...
- webapi中使用token验证(JWT验证)
本文介绍如何在webapi中使用JWT验证 准备 安装JWT安装包 System.IdentityModel.Tokens.Jwt 你的前端api登录请求的方法,参考 axios.get(" ...
- 手写jwt验证,实现java和node无缝切换
前言 前端时间和我朋友写了一个简易用户管理后台,功能其实很简单,涉及到的技术栈有:vue+elementUI,java+spring MVC以及node+egg,数据库用的mysql,简单方便. 一开 ...
- Nginx实现JWT验证-基于OpenResty实现
介绍 权限认证是接口开发中不可避免的问题,权限认证包括两个方面 接口需要知道调用的用户是谁 接口需要知道该用户是否有权限调用 第1个问题偏向于架构,第2个问题更偏向于业务,因此考虑在架构层解决第1个问 ...
- Jwt验证登录
练习模板:https://gitee.com/zh1446802857/swagger-multi-version-api.git Jwt在我的 认知里,是一套门锁.别人(用户)需要用到你的接口 的时 ...
- jwt验证登录信息
为什么要告别session?有这样一个场景,系统的数据量达到千万级,需要几台服务器部署,当一个用户在其中一台服务器登录后,用session保存其登录信息,其他服务器怎么知道该用户登录了?(单点登录), ...
- spring集成jwt验证方式,token验证
为什么要告别session?有这样一个场景,系统的数据量达到千万级,需要几台服务器部署,当一个用户在其中一台服务器登录后,用session保存其登录信息,其他服务器怎么知道该用户登录了?(单点登录), ...
随机推荐
- java 封装及this 用法
封装:主要用于将类中的成员名(类变量)通过 private关键字进行访问权限的设定,使用 private后,成员变量只能在当前类中进行访问,超过该类时访问提示不存在,当然也可以用于方法中,但较少.如果 ...
- 最近公共祖先(LCA)模板
第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每行包含两个正整数x.y,表示x结点和y结点之间有一条直接连接的边(数据保证可以构成树). 接下来M行 ...
- linux grep 的使用
常用的 grep 选项有: -c 只输出匹配行的个数. -i 不区分大小写(只适用于单字符). -h 查询多文件时不显示文件名. -l 查询多文件时只输出包含匹配字符的文件名. ...
- CGLIB 和 JDK生成动态代理类的区别(转)
文章转自http://luyuanliang.iteye.com/blog/1137292 AOP 使用的设计模式就是代理模式,是对IOC设计的补充.为了扩展性,往往会加上反射,动态生成字节码,生成代 ...
- Springmvc导出Excel(maven)
一.导入依赖 <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</ar ...
- PAT A1143 Lowest Common Ancestor (30 分)——二叉搜索树,lca
The lowest common ancestor (LCA) of two nodes U and V in a tree is the deepest node that has both U ...
- 栈(stack)信息
栈在JVM虚拟机中是线程的一块私有空间,比如存储函数的调用信息.局部变量等 特性 先进后出和后进先出即FIFO 借用网络的一个图,感觉看完就可以了解了 最先调用的函数压入栈低,最后压入得函数在栈顶,函 ...
- Python脱产8期 Day03 2019/4/15
一 变量的命名规范 1.只能由 字母, 数字, _, 组成. 2. 不能以数字开头 3.避免与系统关键字重名:重名不会报错,但系统的功能就被自定义的功能屏蔽掉了(严重不建议这样来做) 4.以_开头的 ...
- python 3.6练习题(仿购物车)
opop = [ ('Iphone', 9800), ('Bike', 800), ('Mac Pro', 12000), #定义商品列表 ('Pyhon book', 120), ('Telas', ...
- (转)tcp/ip协议的简单理解 -- ip报文和tcp报文的格式
1.概念: TCP/IP协议通信的过程其实就对应着数据入栈与出栈的过程.入栈的过程,数据发送方每层不断地封装首部与尾部,添加一些传输的信息,确保能传输到目的地.出栈的过程,数据接收方每层不断地拆除首部 ...