JWT(JSON Web Token)是一个非常轻巧的规范,这个规范允许我们使用JWT在用户和服务器之间传递安全可靠的信息,通常使用在HTTP通信过程中进行身份认证。

我们知道,HTTP通信是无状态的,客户端的请求到了服务器处理完之后是无法返回给原来的客户端的,因此需要对访问的客户端进行识别,常用的做法是通过Session机制:客户端在服务端登录成功后,服务端会生成一个sessionId返回给客户端,然后客户端会把这个sessionId存到本地浏览器的Cookie中,当客户端再向服务端发起请求就会从Cookie中取出这个sessionId并附加到请求头中。这样服务端就能够知道是哪个用户发起的请求。

Session存在的问题

1.Session是保存在服务端的,当客户访问量增加的时候,服务端就需要存储大量的Session会话,对响应性能造成影响。

2.当服务器为集群的时候,用户登录其中的一台服务器,会将Session保存到该服务器的内存中,但是当用户访问到其他服务器的时候,因为在该服务器的内存中找不到该Session,就会重新生成一个Session返回给客户端,造成分布式Session共享问题。通常会采用缓存一致性的技术来解决分布式Session的共享问题,或者是使用第三方缓存(比如Redis)来保存Session,其实也可以使用JWT来解决这个问题,也就是使用JWT替代Session。

JWT的产生与使用步骤

1.客户端通过用户名和密码登录服务器。

2.服务端对客户端进行身份验证。

3.服务端对该用户生成Token,返回给客户端。

4.客户端发起请求,需要携带该Token。

5.服务端收到请求后,首先验证Token,然后再返回数据。

6.客户端将Token保存到本地浏览器,一般也是保存到Cookie中。

这样,服务端就不需要保存Token,只需要对Token中携带的信息进行验证即可。

无论客户端访问后台的哪台服务器,只要可以通过用户信息的验证即可。

JWT的原理

JWT的原理是,服务器认证之后,生成一个JSON对象,返回给用户,就像下面这样。

{
"姓名": "张飞",
"角色": "管理员",
"到期时间": "2019年05月20日0时0分"
}

以后用户和服务器进行通信的时候都要发送这个JSON对象。服务器完全只靠这个对象认证用户信息。为了防止用户篡改数据,服务器在生成这个对象的时候,都会加上签名。这样,服务器就不需要保存任何Session会话信息了,也就是说,服务器变成无状态的了,从而比较容易实现扩展。

JWT的数据结构

实际的JWT大概就是像下面这个样子:

这是一个很长的字符串,中间用点分隔符【.】分隔成三个部分(要注意,JWT内部是没有换行的)。

JWT由三个部分组成:头部(Header)、负载(Payload)和签名(Signature)。

Header

Heade部分是一个JSON对象,是描述JWT的元数据。通常是下面这种格式的:

{
"alg": "HS256",
"typ": "JWT"
}

在上面的代码中,alg属性表示签名的算法(Algorithm),默认是HMAC SHA256(写成HS256);typ属性表示这个令牌(token)的类型(type),JWT令牌固定写为JWT。最后,将上面的JSON对象使用Base64URL算法转成字符串。

Payload

Payload部分也是一个JSON对象,用来存放实际需要传递的数据。JWT规定了7个官方字段供选用。

iss(issuer) 签发人
exp(expiration time) 过期时间
sub(subject) 主题
aud(audience) 受众
nbf(not before) 生效时间
iat(issued at) 签发时间
jti(jwt id) 编号

除了这些官方字段,也可以在这个部分定义私有字段:

{
"sub": "buybuybuy",
"name": "yanggb",
"admin": true
}

注意这个JWT部分默认是不加密的,任何人都可以读到,所以不要把秘密信息放在这个部分。

这个JSON对象也要使用Base64URL算法转成字符串。

Signature

Signature部分是对前两部分的签名,防止数据篡改。

首先,需要指定一个密钥(secret)。这个密钥只有服务器才知道,不能泄露给用户。

然后,使用Header里面指定的签名算法(默认是HMAC SHA256),按照下面的公式产生签名:

HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)

最后,在算出签名之后,把Header、Payload、Signature三个部分拼成一个字符串,每个部分之间用点分隔符【.】分割,就可以返回给用户了。

Base64URL算法

前面提到,Header和Payload串型化的算法是Base64URL。这个算法跟Base64算法基本类似,但有一些小的不同。

JWT作为一个令牌(Token),有些场合可能会放到URL(比如api.yanggb.com/?token=xxx)。Base64有三个字符【+】、【/】和【=】,在URL里面是有特殊含义的,所以需要被替换掉:【=】号被省略、【+】号被替换成【-】、【/】被替换成【_】。这就是Base64URL算法和Base64算法的不同。

JWT的使用方式

客户端收到服务端返回的JWT,可以存储在Cookie里面,也可以存储在localStorage里面。此后,客户端每次与服务器通信,都要带上这个JWT。你可以把它放在Cookie里面自动发送,但是这样就不能跨域,所以更好的做法是放在HTTP请求的头信息Authorization字段里面。

Authorization: Bearer <token>

另一种做法是在跨域的时候将JWT放在POST请求的数据体里面。

JWT的几个特点

1.JWT默认是不加密,但是也是可以加密的。生成原始的Token以后,可以用密钥再加密一次。JWT不加密的情况下,不能将秘密数据写入JWT。

2.JWT不仅可以用于认证,也可以用于交换信息。有效地使用JWT,可以降低服务器查询数据库的次数。

3.JWT的最大缺点是由于服务器不保存Session会话状态,因此无法在使用过程中废止某个Token或者更改Token的权限。意思就是说,一旦JWT签发了,在到期之前就会始终有效,除非服务器有部署额外的处理逻辑。

4.JWT本身包含了认证信息,一旦泄露,任何人都可以获得该令牌的所有权限。为了减少盗用,JWT的有效期应该设置得比较短。对于一些比较重要的权限,使用时应该再次对用户进行认证。

5.为了减少盗用,JWT不应该使用HTTP协议明码传输,要使用HTTPS协议传输。

JWT的使用实例(Demo)

在Maven项目中添加JWT的依赖、相关依赖和插件。

<!-- JWT -->
<dependencies>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.0</version>
</dependency> <dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>RELEASE</version>
<scope>compile</scope>
</dependency>
</dependencies> <build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>

创建一个单元测试类。

public class JWTDemo {
// 加密的KEY
private static final String SECRET_KEY = "123456"; @Test
public void jwtTest() throws InterruptedException {
// 创建JWT
long time = System.currentTimeMillis() + 30*60*1000;
String jwt = this.buildJwt(new Date(time));
System.out.println("JWT字符串:" + jwt); // 验证token是否可用
boolean vaild = this.isJwtValid(jwt);
System.out.println("Token可用:" + vaild);
} /**
* 创建JWT
* @param exp 过期时间
* @return JWT String
*/
private String buildJwt(Date exp) {
return Jwts.builder()
.signWith(SignatureAlgorithm.HS256, SECRET_KEY) // SECRET_KEY是加密算法对应的密钥,这里使用额是HS256加密算法
.claim("name", "yanggb")
.setExpiration(exp) // expTime是过期时间
.compact();
} private boolean isJwtValid(String jwt) {
try {
// 解析JWT字符串中的数据,并进行最基础的验证
Claims claims = Jwts.parser()
.setSigningKey(SECRET_KEY) // SECRET_KEY是加密算法对应的密钥,jjwt可以自动判断机密算法
.parseClaimsJws(jwt) // jwt是JWT字符串
.getBody();
System.out.println(claims);
}
// 在解析JWT字符串时,如果密钥不正确,将会解析失败,抛出SignatureException异常,说明该JWT字符串是伪造的
// 在解析JWT字符串时,如果过期时间字段已经早于当前时间,将会抛出ExpiredJwtException异常,说明本次请求已经失效
catch (SignatureException | ExpiredJwtException e) {
return false;
}
return true;
}
}

运行之后就可以在控制台看到打印出来的信息,然后可以使用JWT的解析工具解析出内容(https://jwt.io/):

这些就是JWT的入门知识。

"我以为回忆终究会慢慢搁浅,化作泡沫,消失在时光の海的边陲。可是记忆的种子却时而开花,时而凋零,告诉我们:今后无论去哪,都要勇敢。"

jwt入门的更多相关文章

  1. .net core jwt 入门记录

    从百度里搜索里搜索了很多jwt的文章,跟着文章写了一个demo,这里记录下学习过程中碰上的问题.看文章多遍,不如手工实现一次. 模板已上传到github.com:dogvane/webapi_jwt_ ...

  2. JWT入门简介

    官网:https://jwt.io/ 文档:https://jwt.io/introduction/ 目录 什么是JWT 头部(Header) 载荷(Payload) 签名(Signature) JW ...

  3. 【译】JWT(JSON Web Token) 入门指南

    JWT 入门指南 原文地址:https://blog.angular-university.io/angular-jwt/ 这篇文章是两篇手把手教你如何在Angular应用(也适用于企业级应用)中实现 ...

  4. 阶段5 3.微服务项目【学成在线】_day16 Spring Security Oauth2_12-SpringSecurityOauth2研究-JWT研究-生成私钥和公钥

    3.6.3 JWT入门 Spring Security 提供对JWT的支持,本节我们使用Spring Security 提供的JwtHelper来创建JWT令牌,校验JWT令牌 等操作. 3.6.3. ...

  5. 在gin框架中使用JWT

    在gin框架中使用JWT JWT全称JSON Web Token是一种跨域认证解决方案,属于一个开放的标准,它规定了一种Token实现方式,目前多用于前后端分离项目和OAuth2.0业务场景下. 什么 ...

  6. 【zipkin】链路追踪

    1,安装zipkin:https://zipkin.io/pages/quickstart.html 推荐使用docker去安装zipkin服务,下载安装执行都有了.缺点是下载要等待一段时间 2,使用 ...

  7. PHP 正则表达示

    PHP 正则表达示 php如何使用正则表达式 正则表达式基本元字符 #正则表达式示例 ^:匹配输入字符串开始的位置.如果设置了 RegExp 对象的 Multiline 属性,^ 还会与“\n”或“\ ...

  8. PHP 流程控制

    流程控制 if, else, elseif $a = 5; $b = 9; if ($a > $b): echo "a is bigger than b"; elseif ( ...

  9. JWT的入门案例

    1.什么是JWT? JWT全称JSON Web Token.是为了在网络应用环境键传递声明而执行的一种基于JSON的开放标准. 2.JWT的使用场景? 授权:一旦用户登录,每个后续请求将包括JWT,允 ...

随机推荐

  1. mysql 数据库分表小实例

    项目开发中,我们的数据库数据越来越大,随之而来的是单个表中数据太多.以至于查询书读变慢,而且由于表的锁机制导致应用操作也搜到严重影响,出现了数据库性能瓶颈. 当出现这种情况时,我们可以考虑分表,即将单 ...

  2. yolov3和ssd的区别

    版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/BlowfishKing/article/d ...

  3. 新增SAP到OA接口,OA怎么更新WSDL给PI,怎么选择PI的IP地址(备忘)

    1.首先定义个class. 弄完以后可以使用http://IP地址:8088/seeyon/services/sapService?wsdl  进行导出,部署在哪个服务器就用哪个服务器的IP地址 pr ...

  4. 使用 FiddlerCore 自定义 HTTP/HTTPS 网络代理

    Fiddler 是个很好用的网络请求查看与调试工具,还可以写插件来扩展其功能. Fiddler 插件开发,使用 WPF 作为 UI 控件 - J.晒太阳的猫 - 博客园 但部分场景下,需要自定义很多网 ...

  5. hibernateHQL

    HQL 即Hibernate Query Language的缩写 hql和sql区别/异同 HQL                                                    ...

  6. mysql修改数据 -- 主键冲突

    mysql 插入数据唯一键冲突 前提: 修改数据三种可用的方法解决主键冲突的问题 1. insert into ... on duplicate key update set ... 2. updat ...

  7. 2019年上半年收集到的人工智能GAN干货文章

    2019年上半年收集到的人工智能GAN干货文章 GAN简介及其常见应用 训练GAN,你应该知道的二三事 了解生成对抗网络(GAN) CosmoGAN:训练GAN,让AI寻找宇宙中的暗物质 关于GAN的 ...

  8. Macbook触控板使用技巧

    1. 在Storyboard鼠标右键可以直接拖线的,如果你用的是外接的第三方鼠标,没必要按着 control 键再用鼠标左键拖线 如果是触控板的话,双指按下去就可以直接拖线,带3Dtouch功能的触控 ...

  9. 微信小程序踩坑日记3——上传照片至服务器

    0. 引言 主要解决将小程序端获取的图片保存在服务器上.亲测可用的服务端脚本. 1. 获取照片 通过wx.chooseImage()方法,获取到图片,使用wx.uploadFile()上传图片. wx ...

  10. MySQL数据库(一)索引

    索引的作用是操作数据库时避免全表扫描. 索引的机制 B Tree与B+Tree索引 B(blance) 树可以看作是对2-3查找树的一种扩展,即他允许每个节点有M-1个子节点. 根节点至少有两个子节点 ...