JSON Web Token(缩写 JWT) 目前最流行、最常见的跨域认证解决方案,前端后端都需要会使用的东西
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
的数据共享呢??
- 第一种解决方式就是实现
Session
数据的持久化。各种服务收到请求时,都向数据持久层请求数据,来验证是否是正确的用户。但其实无论我们将Session
存放在服务器哪里,都会增加服务器的负担。这种方案优点就是简单,缺点就是扩展性不好,安全性较差,容易增加服务器的负担。 - 第二种解决方式其实就是
JWT
的方式实现的,所有的数据不在保存到服务器端,而是保存到客户端,每次请求时都携带上Token
令牌。
二、什么是 JWT ?
根据官网介绍:
JSON Web Token (JWT) 是一个开放标准,它定义了一种紧凑且自包含的方式,用于在各方之间作为 JSON 对象安全地传输信息。该信息可以被验证和信任,因为它是经过数字签名的。JWT 可以使用秘密(使用HMAC算法)或使用RSA或ECDSA的公钥/私钥对进行签名。
简单来理解就是 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<String, Object> , 如果您想添加自己的属性,只需使用 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) 目前最流行、最常见的跨域认证解决方案,前端后端都需要会使用的东西相关推荐
- JSON Web Token(缩写 JWT) 目前最流行的跨域认证解决方案
JSON Web Token(缩写 JWT) 目前最流行的跨域认证解决方案 参考文章: (1)JSON Web Token(缩写 JWT) 目前最流行的跨域认证解决方案 (2)https://www. ...
- 后端架构token授权认证机制:spring security JSON Web Token(JWT)简例
后端架构token授权认证机制:spring security JSON Web Token(JWT)简例 在基于token的客户端-服务器端认证授权以前,前端到服务器端的认证-授权通常是基于sess ...
- JSON WEB TOKEN(JWT)的分析
JSON WEB TOKEN(JWT)的分析 一般情况下,客户的会话数据会存在文件中,或者引入redis来存储,实现session的管理,但是这样操作会存在一些问题,使用文件来存储的时候,在多台机器上 ...
- JWT—JSON Web Token - 理解JWT网络间应用用户安全认证交互设计
原文地址:http://blog.leapoahead.com/2015/09/06/understanding-jwt/ 官网地址:https://jwt.io/ JSON Web Token(JW ...
- Json Web Token(JWT)
JsonWebToken 概述 如果各位不了解 JWT,不要紧张,它并不可怕. JSON Web Token(JWT)是一个非常轻巧的规范.这个规范允许我们使用JWT在用户和服务器之间传递安全可靠的信 ...
- php后台跨域token,JSON Web Token(JWT)目前最流行的跨域身份验证解决方案(PHP)类...
JSON Web Token(JWT)是目前最流行的跨域身份验证解决方案,下面我自己封装了一个PHP的Jwt类,直接复制即可使用,无需composer安装包: 常规的身份验证流程为: 该方案的最大的短 ...
- jwt 私钥_什么是 JSON Web Token(JWT)
有关本文档的快速链接,请参考页面提示. 什么是 JSON Web Token(JWT)? JSON Web Token (JWT) 作为一个开放的标准 (RFC 7519) 定义了一种简洁自包含的方法 ...
- JSON web token@04#JWT Claims
兄Die,写代码太累了?孤独寂寞冷?还没有女朋友吧? 关注微信公众号(瓠悠笑软件部落),送知识!送知识!送温暖!送工作!送女朋友!插科打诨哟! 4. JWT Claims JWT Claims Set ...
- JWT(JSON Web Token)的基本原理
JWT(JSON Web Token)的基本原理 JSON Web Token(缩写 JWT)是目前最流行的跨域认证解决方案 一.跨域认证的问题 1.用户向服务器发送用户名和密码. 2.服务器验证通过 ...
最新文章
- 免费送书啦!玩转3D视界,这本书带你感知立体的世界
- python+HDF5+h5py
- thirft支持双向通信
- 分支结构,循环结构,for循环,九九乘法表
- 如何在参考文献中优雅地引用URL?How do you get nicely formatted URLs in the bibliography?
- [转] 做一个让人欣赏的女子
- php中的字符串可以当做数组调用
- ansys软件linux安装教程,ansys 15 for linux 安装纪录
- 斐讯手表怎么刷机华为系统_智能手表怎么刷机?
- DBSCAN聚类算法
- web前端项目 - cypress自动化测试运行构建
- 《苏菲的世界》读书笔记之一:自然派哲学家
- 北京市车管所及车管分所办公电话
- A1012 The Best Rank
- 使用v-cli创建项目,引入element-ui构建用户管理页面实现增删改查
- 怎么去视频水印?一键去除视频水印
- java转大写_java实现数字转大写的方法
- tl wn322g linux驱动下载,TL-WN322G+驱动
- 博图用到c语言了吗,浅谈西门子TIA博图软件
- kali 利用msf通过win7永恒之蓝漏洞获取权限
热门文章
- 一滴油怎样造就了一种健康生活方式?
- 阅读APP,为什么都开始抢kindle生意了?
- pythonpostapi_python post接口测试第一个用例日记
- 云痕大数据 家长登录_云痕家长app
- python中的几种copy用法_Python3中copy模块常用功能及其他几种copy方式比较
- c 一般处理程序 ajax,Ajax调用一般处理程序数据
- earcharts tree 节点间隔_InnoDB是顺序查找B-Tree叶子节点的吗?
- outguess秘钥加密--[BJDCTF 2nd]圣火昭昭-y1ng
- python下timer定时器常用的两种实现方法
- Python | 除法