JSON Web Token(缩写 JWT)是目前最流行,也是最常见的跨域认证解决方案。无论是咱们后端小伙伴,还是前端小伙伴对都是需要了解。
本文介绍它的原理、使用场景、用法。

关于封面:这个冬天你过得开心吗

一、跨域认证的问题

1.1、常见的前后端认证方式

  • Session-Cookie
  • Token 验证(包括JWT,SSO)
  • OAuth2.0(开放授权)

1.2、Session-Cookie实现方式

流程大致如下:

1、用户向服务器发送用户名和密码。

2、服务器验证通过后,在当前对话(session)里面保存相关数据,比如用户角色、登录时间等等。

3、服务器向用户返回一个 session_id,写入用户的 Cookie

4、用户随后的每一次请求,都会通过 Cookie,将 session_id传回服务器。

5、服务器收到 session_id,找到前期保存的数据,由此得知用户的身份。

这种模式在单机时不存在什么问题,但是一旦服务器变为集群模式时,或者是跨域的服务器时,这个时候Session就必须实现数据共享。

这个时候就要考虑每台服务器如何实现对 Session 的数据共享呢??

  1. 第一种解决方式就是实现 Session 数据的持久化。各种服务收到请求时,都向数据持久层请求数据,来验证是否是正确的用户。但其实无论我们将 Session 存放在服务器哪里,都会增加服务器的负担。这种方案优点就是简单,缺点就是扩展性不好,安全性较差,容易增加服务器的负担。
  2. 第二种解决方式其实就是 JWT 的方式实现的,所有的数据不在保存到服务器端,而是保存到客户端,每次请求时都携带上 Token 令牌。

二、什么是 JWT ?

根据官网介绍:

JSON Web Token (JWT) 是一个开放标准,它定义了一种紧凑且自包含的方式,用于在各方之间作为 JSON 对象安全地传输信息。该信息可以被验证和信任,因为它是经过数字签名的。JWT 可以使用秘密(使用HMAC算法)或使用RSAECDSA的公钥/私钥对进行签名

简单来理解就是 JWT 就是一个JSON对象经过加密和签名的,可以在网络中安全的传输信息,并且可以被验证和信任。

2.1、什么时候应该使用 JWT ?

我目前用的最多的地方就是在授权方面,这也是 JWT 最常见的场景,其次还可以用来交换信息。

授权例子:

用户登录后,服务器端返回一个JWT,用户保存在本地,之后的每次请求都将包含JWT,服务器验证用户携带的JWT,来判断是否允许访问服务和资源。

另外,单点登录(SSO) 也是当今广泛使用JWT的一项功能,就是在A网站登录后,在B网站也能够实现自动登录,而不需要重复登录,如你在淘宝登录了,在身份没有过期前,你去看天猫网站,也会发现你已经登录了。

简而言之:用户只需要登录一次就可以访问所有相互信任的应用系统。并且能够轻松跨不同域使用,服务器也不需要存储session相关信息,减轻了负担

2.2、JWT 原理

其实 JWT 的原理就是,服务器认证以后,将一个 JSON 对象加密成一个紧凑的字符串(Token),发回给用户,就像下面这样。

// JSON 对象
{"姓名": "王五","角色": "管理员","到期时间": "2021年9月21日0点0分"
}
//加密后
eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJ1c2VybmFtZSIsIm5iZiI6MTYzMjI3NzU1NCwiaXNzIjoiY3J1c2giLCJleHAiOjE2MzIyNzc2NTQsImRlbW8iOiLlj6_lrZjlgqjkv6Hmga8iLCJpYXQiOjE2MzIyNzc1NTQsImRlbW8yIjoi5Y-v5a2Y5YKo5L-h5oGvMiJ9.OuqG5Ha_Ofmh5R9Et1vqLYSAlIO85oW9D9Jq9cKKYODO643ZLiDTyQs8dl3PLsZ-_5t0xv6kfKhCzCkCYznBNA

在认证之后,用户和服务器通信时,每次都会携带上这个Token。服务器端不再存储session信息,完全依靠用户携带的Token来判断用户身份。为了安全,服务器在生成Token的时候,都会加上一个数字签名。

这样做的优势:服务器不需要再保存 session数据,减轻了服务器负担,并且基于 JWT 认证机制的应用不需要去考虑用户在哪一台服务器登录,为应用的扩展提供了便利。

2.3、JWT 数据结构

JSON Web Tokens 由用点 ( .)分隔的三个部分组成,它们是:

  • Header(头部)
  • Payload(负载)
  • Signature(签名)

因此,JWT 通常如下所示。注意:实际上是未分行的,这里是为了便于展示。

xxxxx.yyyyy.zzzzz
如:
eyJhbGciOiJIUzUxMiJ9.
eyJzdWIiOiJ1c2VybmFtZSIsIm5iZiI6MTYzMjI3NzU1NCwiaXNzIjoiY3J1c2giLCJleHAiOjE2MzIyNzc2NTQsImRlbW8iOiLlj6_lrZjlgqjkv6Hmga8iLCJpYXQiOjE2MzIyNzc1NTQsImRlbW8yIjoi5Y-v5a2Y5YKo5L-h5oGvMiJ9.
OuqG5Ha_Ofmh5R9Et1vqLYSAlIO85oW9D9Jq9cKKYODO643ZLiDTyQs8dl3PLsZ-_5t0xv6kfKhCzCkCYznBNA

2.3.1、Header (标题)

jwt的头部承载两部分信息:

  • 声明类型,这里是jwt
  • 声明加密的算法 通常直接使用 HMAC SHA256

Header 部分是一个 JSON 对象,描述 JWT 的元数据,通常是下面的样子。

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

上面代码中,alg属性表示签名的算法(algorithm),默认是 HMAC SHA256(写成 HS256);typ属性表示这个令牌(token)的类型(type),JWT 令牌统一写为JWT

2.3.2、Payload(有效载荷)

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

  • iss (issuer):签发人
  • exp (expiration time):过期时间
  • sub (subject):主题 jwt所面向的用户
  • aud (audience):受众 接收jwt的一方
  • nbf (Not Before):生效时间
  • iat (Issued At):签发时间
  • jti (JWT ID):编号,jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。

除了官方字段,你还可以在这个部分定义私有字段,下面就是一个例子。

{"sub": "1234567890","name": "John Doe","admin": true
}

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

2.3.3、Signature(签名)

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

首先,需要指定一个密钥(secret)。这个密钥只有服务器才知道,不能泄露给用户。然后,使用 Header 里面指定的签名算法(默认是 HMAC SHA256),按照下面的公式产生签名。

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

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

注意:签名用于验证消息在此过程中没有更改,并且在使用私钥签名的令牌的情况下,它还可以验证 JWT 的发送者是它所说的人。secret是保存在服务器端的,jwt的签发生成也是在服务器端的,secret就是用来进行jwt的签发和jwt的验证的关键,所以,它就是我们服务端的私钥,在任何场景都不应该泄露出去。一旦客户端得知这个secret, 那就意味着客户端是可以自我签发jwt了,那么安全将不复存在。

2.3.4、 Base64URL

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

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

2.4、JWT工具类

相关依赖:

<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.0</version>
</dependency>

如果是Jdk11使用的话,可能会报这样的一个错误:

Exception in thread "main" java.lang.NoClassDefFoundError: javax/xml/bind/DatatypeConverterat io.jsonwebtoken.impl.Base64Codec.decode(Base64Codec.java:26)at io.jsonwebtoken.impl.DefaultJwtBuilder.signWith(DefaultJwtBuilder.java:99)at com.crush.jwt.utils.JwtUtils.createJwt(JwtUtils.java:47)at com.crush.jwt.utils.JwtUtils.main(JwtUtils.java:127)
Caused by: java.lang.ClassNotFoundException: javax.xml.bind.DatatypeConverterat java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:581)at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)... 4 more

好像是因为Jdk11中没有这个类了,得加上下面这样的一个依赖:

<dependency><groupId>javax.xml.bind</groupId><artifactId>jaxb-api</artifactId><version>2.3.0</version>
</dependency>

工具类

import io.jsonwebtoken.*;import java.util.Date;
import java.util.HashMap;/*** @Author: crush* @Date: 2021-09-21 22:18* version 1.0*/
public class JwtUtils {/*** 服务器端密钥*/private static final String SECRET = "jwtsecretdemo";/*** 颁发者*/private static final String ISS = "crush";/*** 这里创建用到的时间、用户名、应该是传入进来的,* 登录时选择是否记住我,过期时间应当是不一致的。* @return*/public static String createJwt() {HashMap<String, Object> map = new HashMap<>();map.put("demo", "可存储信息");map.put("demo2","可存储信息2");String jwt = Jwts.builder().setClaims(map)// jwt所面向的用户.setSubject("username")//设置颁发者.setIssuer(ISS)// 定义在什么时间之前,该jwt都是不可用的..setNotBefore(new Date())//签发时间.setIssuedAt(new Date())//设置 JWT 声明exp (到期)值.setExpiration(new Date(System.currentTimeMillis() + 100000)).signWith(SignatureAlgorithm.HS512, SECRET)//实际构建 JWT 并根据JWT 紧凑序列化 规则将其序列化为紧凑的、URL 安全的字符串。.compact();return jwt;}/*** 获取 Claims 实例* Claims :一个 JWT声明集 。*   这最终是一个 JSON 映射,可以向其中添加任何值,但为了方便起见,JWT 标准名称作为类型安全的 getter 和 setter 提供。*   因为这个接口扩展了Map&lt;String, Object&gt; , 如果您想添加自己的属性,只需使用 map 方法,*   例如:*      claims.put("someKey", "someValue");** @param jwt* @return*/public static Claims getBody(String jwt) {return Jwts.parser().setSigningKey(SECRET).parseClaimsJws(jwt).getBody();}/*** 判断 JWT 是否已过期** @param jwt* @return*/public static boolean isExpiration(String jwt) {return getBody(jwt)//返回 JWT exp (到期)时间戳,如果不存在则返回null 。.getExpiration()//测试此日期是否在指定日期之前。.before(new Date());}/*** Subject:获取 jwt 所面向的用户** @param jwt* @return*/public static String getSubject(String jwt) {return getBody(jwt).getSubject();}/*** Issuer:获取颁发者** @param jwt* @return*/public static String getIssuer(String jwt) {return getBody(jwt).getIssuer();}/*** getClaimsValue** @param jwt* @return*/public static String getClaimsValue(String jwt) {return (String) getBody(jwt).get("demo");}/*** getClaimsValue** @param jwt* @return*/public static String getClaimsValue2(String jwt) {return (String) getBody(jwt).get("demo2");}public static void main(String[] args) {String jwt = createJwt();System.out.println(jwt);System.out.println("jwt 是否已经过期:"+isExpiration(jwt));System.out.println("Claims 中所存储信息:"+getBody(jwt).toString());System.out.println("jwt 所面向的用户:"+getSubject(jwt));System.out.println("jwt 颁发者:"+getIssuer(jwt));System.out.println("通过键值,取出我们自己放进 Jwt 中的信息:"+getClaimsValue(jwt));System.out.println("通过键值,取出我们自己放进 Jwt 中的信息2:"+getClaimsValue2(jwt));}
}

三、如何应用

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

Authorization: Bearer <token>

一般是在请求头里加入Authorization,并加上Bearer标注:

fetch('api/user/1', {headers: {'Authorization': 'Bearer ' + token}
})

服务端会验证token,如果验证通过就会返回相应的资源。整个流程就是这样的:

实际使用过程中,我们通常是结合着Security安全框架一起使用的,大家感兴趣的话,可以来一起看看我写的这篇文章。

SpringBoot整合Security安全框架、控制权限

也可以直接看源码:Security-Gitee

四、总结

4.1、优点:

  • 因为json的通用性,JWT支持多语言,像JAVA,JavaScript,NodeJS,PHP等很多语言都可以使用。
  • 因为有了payload部分,所以JWT可以在自身存储一些其他业务逻辑所必要的非敏感信息。
  • 可以用于交换信息。有效使用 JWT,可以降低服务器查询数据库的次数。
  • 便于传输,jwt的构成非常简单,字节占用很小,所以它是非常便于传输的。
  • 它不需要在服务端保存会话信息, 所以它易于应用的扩展

4.2、安全相关:

  • 保护好secret私钥,该私钥非常重要。如果密钥泄露,用户自己即可颁布JWT令牌,安全将不复存在。
  • 如果条件允许,JWT 不应该使用 HTTP 协议明码传输,而是要使用 HTTPS 协议传输。Https协议更安全。
  • JWT 的有效期应该设置得比较短。对于一些比较重要的权限,使用时应该再次对用户进行认证。

4.3、缺点:

  • JWT 的最大优点是不需要在服务端保存会话信息,最大的缺点也是如此,由于服务器不保存 session 状态,因此无法在使用过程中废止某个 token,或者更改 token 的权限。也就是说,一旦 JWT 签发了,在到期之前就会始终有效。

五、自言自语

本文就是简单介绍了,具体使用具体情况具体分析啦。

你好,我是博主宁在春:主页

希望本篇文章能让你感到有所收获!!!

我们:待别日相见时,都已有所成

参考

jwt

JSON Web Token 入门教程

JSON Web Token(缩写 JWT) 目前最流行、最常见的跨域认证解决方案,前端后端都需要会使用的东西相关推荐

  1. JSON Web Token(缩写 JWT) 目前最流行的跨域认证解决方案

    JSON Web Token(缩写 JWT) 目前最流行的跨域认证解决方案 参考文章: (1)JSON Web Token(缩写 JWT) 目前最流行的跨域认证解决方案 (2)https://www. ...

  2. 后端架构token授权认证机制:spring security JSON Web Token(JWT)简例

    后端架构token授权认证机制:spring security JSON Web Token(JWT)简例 在基于token的客户端-服务器端认证授权以前,前端到服务器端的认证-授权通常是基于sess ...

  3. JSON WEB TOKEN(JWT)的分析

    JSON WEB TOKEN(JWT)的分析 一般情况下,客户的会话数据会存在文件中,或者引入redis来存储,实现session的管理,但是这样操作会存在一些问题,使用文件来存储的时候,在多台机器上 ...

  4. JWT—JSON Web Token - 理解JWT网络间应用用户安全认证交互设计

    原文地址:http://blog.leapoahead.com/2015/09/06/understanding-jwt/ 官网地址:https://jwt.io/ JSON Web Token(JW ...

  5. Json Web Token(JWT)

    JsonWebToken 概述 如果各位不了解 JWT,不要紧张,它并不可怕. JSON Web Token(JWT)是一个非常轻巧的规范.这个规范允许我们使用JWT在用户和服务器之间传递安全可靠的信 ...

  6. php后台跨域token,JSON Web Token(JWT)目前最流行的跨域身份验证解决方案(PHP)类...

    JSON Web Token(JWT)是目前最流行的跨域身份验证解决方案,下面我自己封装了一个PHP的Jwt类,直接复制即可使用,无需composer安装包: 常规的身份验证流程为: 该方案的最大的短 ...

  7. jwt 私钥_什么是 JSON Web Token(JWT)

    有关本文档的快速链接,请参考页面提示. 什么是 JSON Web Token(JWT)? JSON Web Token (JWT) 作为一个开放的标准 (RFC 7519) 定义了一种简洁自包含的方法 ...

  8. JSON web token@04#JWT Claims

    兄Die,写代码太累了?孤独寂寞冷?还没有女朋友吧? 关注微信公众号(瓠悠笑软件部落),送知识!送知识!送温暖!送工作!送女朋友!插科打诨哟! 4. JWT Claims JWT Claims Set ...

  9. JWT(JSON Web Token)的基本原理

    JWT(JSON Web Token)的基本原理 JSON Web Token(缩写 JWT)是目前最流行的跨域认证解决方案 一.跨域认证的问题 1.用户向服务器发送用户名和密码. 2.服务器验证通过 ...

最新文章

  1. 免费送书啦!玩转3D视界,这本书带你感知立体的世界
  2. python+HDF5+h5py
  3. thirft支持双向通信
  4. 分支结构,循环结构,for循环,九九乘法表
  5. 如何在参考文献中优雅地引用URL?How do you get nicely formatted URLs in the bibliography?
  6. [转] 做一个让人欣赏的女子
  7. php中的字符串可以当做数组调用
  8. ansys软件linux安装教程,ansys 15 for linux 安装纪录
  9. 斐讯手表怎么刷机华为系统_智能手表怎么刷机?
  10. DBSCAN聚类算法
  11. web前端项目 - cypress自动化测试运行构建
  12. 《苏菲的世界》读书笔记之一:自然派哲学家
  13. 北京市车管所及车管分所办公电话
  14. A1012 The Best Rank
  15. 使用v-cli创建项目,引入element-ui构建用户管理页面实现增删改查
  16. 怎么去视频水印?一键去除视频水印
  17. java转大写_java实现数字转大写的方法
  18. tl wn322g linux驱动下载,TL-WN322G+驱动
  19. 博图用到c语言了吗,浅谈西门子TIA博图软件
  20. kali 利用msf通过win7永恒之蓝漏洞获取权限

热门文章

  1. 一滴油怎样造就了一种健康生活方式?
  2. 阅读APP,为什么都开始抢kindle生意了?
  3. pythonpostapi_python post接口测试第一个用例日记
  4. 云痕大数据 家长登录_云痕家长app
  5. python中的几种copy用法_Python3中copy模块常用功能及其他几种copy方式比较
  6. c 一般处理程序 ajax,Ajax调用一般处理程序数据
  7. earcharts tree 节点间隔_InnoDB是顺序查找B-Tree叶子节点的吗?
  8. outguess秘钥加密--[BJDCTF 2nd]圣火昭昭-y1ng
  9. python下timer定时器常用的两种实现方法
  10. Python | 除法