理解 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库。 然后我正在创建一个名为appconst,它将使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的路由。 与之前使用getlisten的部分中的路由不同,此路由将使用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验证的更多相关文章

  1. 踩坑之路---JWT验证

    使用JWT验证客户的携带的token 客户端在请求接口时,需要在request的head中携带一个token令牌 服务器拿到这个token解析获取用户资源,这里的资源是非重要的用户信息 目前我的理解, ...

  2. golang学习笔记10 beego api 用jwt验证auth2 token 获取解码信息

    golang学习笔记10 beego api 用jwt验证auth2 token 获取解码信息 Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放 ...

  3. springboot成神之——basic auth和JWT验证结合

    本文介绍basic auth和JWT验证结合 目录结构 依赖 config配置文件WebSecurityConfig filter过滤器JWTLoginFilter filter过滤器JWTAuthe ...

  4. webapi中使用token验证(JWT验证)

    本文介绍如何在webapi中使用JWT验证 准备 安装JWT安装包 System.IdentityModel.Tokens.Jwt 你的前端api登录请求的方法,参考 axios.get(" ...

  5. 手写jwt验证,实现java和node无缝切换

    前言 前端时间和我朋友写了一个简易用户管理后台,功能其实很简单,涉及到的技术栈有:vue+elementUI,java+spring MVC以及node+egg,数据库用的mysql,简单方便. 一开 ...

  6. Nginx实现JWT验证-基于OpenResty实现

    介绍 权限认证是接口开发中不可避免的问题,权限认证包括两个方面 接口需要知道调用的用户是谁 接口需要知道该用户是否有权限调用 第1个问题偏向于架构,第2个问题更偏向于业务,因此考虑在架构层解决第1个问 ...

  7. Jwt验证登录

    练习模板:https://gitee.com/zh1446802857/swagger-multi-version-api.git Jwt在我的 认知里,是一套门锁.别人(用户)需要用到你的接口 的时 ...

  8. jwt验证登录信息

    为什么要告别session?有这样一个场景,系统的数据量达到千万级,需要几台服务器部署,当一个用户在其中一台服务器登录后,用session保存其登录信息,其他服务器怎么知道该用户登录了?(单点登录), ...

  9. spring集成jwt验证方式,token验证

    为什么要告别session?有这样一个场景,系统的数据量达到千万级,需要几台服务器部署,当一个用户在其中一台服务器登录后,用session保存其登录信息,其他服务器怎么知道该用户登录了?(单点登录), ...

随机推荐

  1. [ISE 14.7]Fail to Link the designer导致无法仿真问题

    一.当前配置 操作系统:WIN 8.1 64位 软件:Xilinx ISE 14.7 二.解决方法 首先,似乎64位的binary都有些问题,所以先把ISE Design Suite 14.7这个快捷 ...

  2. mysql 拒绝访问的解决办法

    java.sql.SQLException: null,  message from server: "Host 'xxx' is not allowed to connect to thi ...

  3. Django基础之urls

    一  Django简介 二   视图层之应用系统 一  Django简介 Django:   urls:路径与视图函数的映射关系   views:逻辑处理   models:与数据库相关的操作   t ...

  4. UVA10562-Undraw the Trees(递归)

    Problem UVA10562-Undraw the Trees Accept: 1199  Submit: 8397 Time Limit: 3000 mSec Problem Descripti ...

  5. 最近公共祖先(LCA)模板

    第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每行包含两个正整数x.y,表示x结点和y结点之间有一条直接连接的边(数据保证可以构成树). 接下来M行 ...

  6. YOLO(5) YOLO2 代码讲解

    运行 darknet-rect2.exe detector demo F:/2Project/YOLO/yolo2/3data/TestData/data/voc.data F:/2Project/Y ...

  7. go标准库的学习-net/rpc/jsonrpc

    参考:https://studygolang.com/pkgdoc 导入方式: import "net/rpc/jsonrpc" jsonrpc包实现了JSON-RPC的Clien ...

  8. rac添加新节点的步骤与方法

    [转载] https://www.cnblogs.com/hankyoon/p/5174465.html OS: [root@rac ~]# more /etc/oracle-releaseOracl ...

  9. JavaScript高级程序设计学习(二)之基本概念

    任何语言的核心都必然会描述这门语言基本的工作原理.而描述的内容通常都要涉及这门语 言的语法.操作符.数据类型.内置功能等用于构建复杂解决方案的基本概念.如前所述, ECMA-262通过叫做 ECMAS ...

  10. ubuntu16.04下zabbix安装和配置

    介绍 Zabbix是用于网络和应用的开源监控软件. 它提供从服务器,虚拟机和任何其他类型的网络设备收集的数千个度量的实时监控. 这些指标可以帮助您确定IT基础架构的当前运行状况,并在客户投诉之前检测硬 ...