浅谈JWT
JWT
常见的认证机制
HTTP Basic Auth
HTTP Basic Auth简单点说明就是每次请求API时都提供用户的username和password,简言之,Basic Auth是配合RESTful API 使用的最简单的认证方式,只需提供用户名密码即可,但由于有把用户名密码暴露给第三方客户端的风险,在生产环境下被使用的越来越少。因此,在开发对外开放的RESTful API时,尽量避免采用HTTP BasicAuth.
Cookie Auth
Cookie认证机制就是为一次请求认证在服务端创建—个Session对象,同时在客户端的浏览器端创建了一个Cookie对象;通过客户端带上来Cookie对象来与服务器端的session对象匹配来实现状态管理的。默认的,当我们关闭浏览器的时候,cookie会被删除。但可以通过修改cookie 的expire time使cookie在一定时间内有效。

OAuth
OAuth(开放授权,Open Authorization)是一个开放的授权标准,允许用户让第三方应用访问该用户在某web服务上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用。如网站通过微信、微博登录等,主要用于第三方登录。
OAuth允许用户提供一个令牌,而不是用户名和密码来访问他们存放在特定服务提供者的数据。每一个令牌授权一个特定的第三方系统(例如,视频编辑网站)在特定的时段(例如,接下来的2小时内)内访问特定的资源(例如仅仅是某一相册中的视频)。这样,OAuth上用户可以授权第三方网站访问他们存储在另外服务提供者的某些特定信息,而非所有内容。
下面是OAuth2.0的流程:

但是这种OAuth的认证机制适用于个人消费者类型的互联网产品,如社交类APP等应用,但是不适合拥有自有认证权限管理的企业应用。
缺点:过重。
Token Auth
使用基于 Token 的身份验证方法,在服务端不需要存储用户的登录记录。大概的流程是这样的:
- 客户端使用用户名跟密码请求登录
- 服务端收到请求,去验证用户名与密码
- 验证成功后,服务端会签发一个 Token,再把这个 Token 发送给客户端
- 客户端收到 Token 以后可以把它存储起来,比如放在 Cookie 里
- 客户端每次向服务端请求资源的时候需要带着服务端签发的 Token
- 服务端收到请求,然后去验证客户端请求里面带着的 Token,如果验证成功,就向客户端返回请求的数据
Token Auth 认证流程

优点
比第一种方式更安全,比第二种方式更节约服务器资源,比第三种方式更加轻量。
具体,Token Auth的优点 (Token机制相对于Cookie机制又有什么好处呢?):
-
支持跨域访问:Cookie是不允许垮域访问的,这一点对Token机制是不存在的,前提是传输的用户认证信息通过HTTP头传输。
-
无状态(也称:服务端可扩展行):Token机制在服务端不需要存储session信息,因为Token 自身包含了所有登录用户的信息,只需要在客户端的cookie或本地介质存储状态信息.
-
更适用CDN:可以通过内容分发网络请求你服务端的所有资料(如:javascript,HTML,图片等),而你的服务端只要提供API即可.
-
去糖:不需要绑定到一个特定的身份验证方案。Token可以在任何地方生成,只要在你的API被调用的时候,你可以进行Token生成调用即可心
-
更适用于移动应用:当你的客户端是一个原生平台 (iOS, Android, Windows 10等)时,Cookie是不被支持的(你需要通过Cookie容器进行处理),这时采用Tokeni人证机制就会简单得多。
-
CSRF:因为不再依赖于Cookie, 所以你就不需要考虑对CSRF(跨站请求伪造)的防范。
-
性能:一次网络往返时间(通过数据库查询session信息)总比做一次HMACSHA256计算的Token验证和解析要费时得多.
-
不需要为登录页面做特殊处理:如果你使用Protractor 做功能测试的时候,不再需要为登录页面做特殊处理,
-
基于标准化;你的AP可以采用标准化的JSON Web Token (WT). 这个标准已经存在多个后端库 (.NET, Ruby.Java.Python,PHP)和多家公司的支持(如:Firebase,Google. Microsoft)
JWT简介
JSON Web Token (JWT)是一个开放的行业标准 (RFC 7519),它定义了一种简介的、自包含的协议格式,用于在通信双方传递json对象,传递的信息经过数字签名可以被验证和信任。
JWT可以使用HMAC算法或使用RSA的公钥/私钥对来签名,防止被篡改。
标准:https://tools.ietf.org/html/rfc7519
JWT令牌的优点:
- Jwt 基于 json,非常方便解析。
- 可以在令牌中自定义丰富的内容,易扩展。
- 通过非对称加密算法及数字签名技术,JWT防止篡改,安全性高。
- 资源服务使用IWT可不依赖认证服务即可完成授权。
缺点:
- JWT令牌较长,古存储空间比较大。
JWT组成

一个JWT其实就是一个字符串,它由头部、负载与签名组成。
Header 头部

头部用于描述关于该JWT的最基本的信息,例如其类型(即WT)以及签名所用的算法(如HMAC SHA256或RSA) 等。
这也可以被表示成一个JSON对象。
{
"alg":"H5256"
"typ":"JWT"
}
-
alg:签名的算法,这里使用的算法是HS256算法
-
typ:是类型。
我们对头部的Json字符串进行BASE64编码(网上有很多在线编码的网站),编码后的字符串如下:

Base64 是一种基于64个可打印字符来表示二进制数据的表示方法。
由于2的6次方等于64,所以每6个比特为个单元,对应某个可打印字符。三个字节有24个比特,对应于4个Base64单元,即3个字节需要用4个可打印字符来表示。
JDK 中提供了非常方便的 BASE64Encoder
和 BASE64Decoder
用它们可以非常方便的完成基于BASE54 的编码和解码。
Payload 负载
第二部分是,就是存放有效信息的地方。这个名字像是特指飞机上承载的货品,这些有效信息包含三个部分:
- 标准中注册的声明(建议但不强制使用)
iss: jwt签发者
sub:jwt所面向的用户
aud:接收jwt的一方
exp:jwt的过期时间,这个过期时间必须要大于签发时间
nbf:定义在什么时间之前,该jwt都是不可用的。
iat: jwt的签发时间
jti:jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。
- 公共的声明
公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息.但不建议添加敏感信息,因为该部分在客户端可解密。
- 私有的声明
私有声明是提供者和消费者所共同定义的声明,一般不建议存放敏感信息,因为base64是对称解密的,意味着该部分信息可以归类为明文信息。
这个指的就是自定义的claim。比如下面那个举例中的name都属于自定的claim。
这些claim跟JWT标准规定的claim区别在于:JWT规定的claim,JWT的接收方在拿到JWT之后,都知道怎么对这些标准的claim进行验证(还不知道是否能够验证);
而private claims不会验证,除非明确告诉接收方要对这些claim进行验证以及规则才行。
{
"sub": "1234567890",
"name": "John Doe",
"admin": true
}
其中sub 是标准声明,name是自定义的声明(公共或私有的)
然后将其进行BASE64编码,得到JWT的第二部分


官网也给我们提示不要存放一些敏感的信息。
Signature 签名/签证
JWT的第三部分的信息是签名,这个签名信息包含三部分:
- header(BASE64之后)
- playload(BASE64之后)
- secret(盐,一定要保密)
这个部分需要base64加密后的header和base64加密后的payload使用,连接組成的字符串,然后通过header中声明的加密方式进行加盐secret组合加密,然后就构成了jwt的第三部分:
8HI-LodOncfVDnbKIPJJqLH998duF9DSDGkx3gRPNVI
将这三部分用,连接成—个完整的字符串,构成了最终的Jwt:
注意:secret 是保存在服务器端的,jwt 的签发生成也是在服务器端的,secret 就是用来进行 jwt 的签发和jwt 的验证,所以,它就是你服务端的私钥,在任何场景都不应该流露出去。一旦客户端得知这个secret,那就意味着客户端是可以自我签发 jwt了。
这是它官网的一个例子。
SpringBoot整合jwt
使用的这个依赖。

文档和源码
https://github.com/bearbrick0/SpringBoot-JJWT-DEMO
SpringSecurityOAuth2整合JWT
项目和文档:https://github.com/bearbrick0/SpringSecurityOauth2_demo
实现AcessToken转换成JwtToken。

拿着这段token去jwt官网解析,

单点登陆SSO
项目和文档:
https://github.com/bearbrick0/SpringSecurityOAuth2-SSO

作者:BearBrick0
出处:https://www.cnblogs.com/bearbrick0/p/16136429.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)