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保存其登录信息,其他服务器怎么知道该用户登录了?(单点登录), ...
随机推荐
- 「PKUSC2018」神仙的游戏
题目链接 比如说上面\(|S|\)为12的字符串,我们欲求出\(f(9)\)的值,那么上面相同颜色的字符必须两两能够匹配.也就是说,同种颜色的字符集里不能同时出现0和1.如果只考虑同种颜色集里相邻的两 ...
- Unity手游之路手游代码更新策略探讨
版权声明: https://blog.csdn.net/janeky/article/details/25923151 这几个月公司项目非常忙.加上家里事情也多,所以blog更新一直搁置了. 近期在项 ...
- Git提交新项目
Github或者码云上新建项目 $ git init $ git add * $ git remote add origin https://gitee.com/demo/demo.git $ git ...
- Spark本地运行成功,集群运行空指针异。
一个很久之前写的Spark作业,当时运行在local模式下.最近又开始处理这方面数据了,就打包提交集群,结果频频空指针.最开始以为是程序中有null调用了,经过排除发现是继承App导致集群运行时候无法 ...
- 帝国CMS 列表模板页面 list.var 内容截取
每天学习一点点 编程PDF电子书免费下载: http://www.shitanlife.com/code list.var 中没有好的办法,只能用程序代码来实现.将整个HTML以一个变量来拼接.如下: ...
- mha高可用以及读写分离
一.MHA简介 二.工作流程 三.MHA架构图 四.MHA工具介绍 五.基于GTID的主从复制 六.部署MHA 七.配置VIP漂移 八.配置binlog-server 九.MySQL中间件Atlas ...
- ucml设置列表分页类型
aginationCtype 分页栏显示效果配置,取值为UCML.Pagination或UCML.PaginationMin,默认为UCML.PaginationMin,在视图显示前设置. 1.pag ...
- Java中static、final、static final的区别【转】
说明:不一定准确,但是最快理解. final: final可以修饰:属性,方法,类,局部变量(方法中的变量) final修饰的属性的初始化可以在编译期,也可以在运行期,初始化后不能被改变. final ...
- Python虚拟环境和包管理工具Pipenv的使用详解--看完这一篇就够了
前言 Python虚拟环境是一个虚拟化,从电脑独立开辟出来的环境.在这个虚拟环境中,我们可以pip安装各个项目不同的依赖包,从全局中隔离出来,利于管理. 传统的Python虚拟环境有virtualen ...
- NodeJS之path模块
NodeJS之path模块 常用的主要有如下工具函数: 1. path.basename(path[, ext]) 2. path.extname(path) 3. path.dirname(path ...