博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
认识和使用JWT
阅读量:3890 次
发布时间:2019-05-23

本文共 5610 字,大约阅读时间需要 18 分钟。

1.前言:

后端项目中总会有长期保存登录状态的需求,相对于保存帐号密码来说,使用token来保存登录状态已经成为业内共识。在如今微服务和多终端以及Restful Api流行的情况下,cookie和session无法应付,又使得token更加流行。不过如何安全的发放token呢?jwt给了一种思路。

2.什么是token?

Token是服务端生成的一串字符串,以作客户端进行请求的一个令牌,当第一次登录后,服务器生成一个Token便将此Token返回给客户端,以后客户端只需带上这个Token前来请求数据即可,无需再次带上用户名和密码。(抄自:)

3.什么是jwt:

官网:

Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).定义了一种简洁的,自包含的方法用于通信双方之间以JSON对象的形式安全的传递信息。因为数字签名的存在,这些信息是可信的,JWT可以使用HMAC算法或者是RSA的公私秘钥对进行签名,是目前最流行的跨域认证解决方案。(抄自)

4.为什么使用jwt:

4.1和cookie,session来对比一下:

互联网服务离不开用户认证。一般流程是下面这样。

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

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

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

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

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

这种模式的问题在于,扩展性(scaling)不好。单机当然没有问题,如果是服务器集群,或者是跨域的服务导向架构,就要求 session 数据共享,每台服务器都能够读取 session。而且存在伪造跨站请求伪造攻击的风险

举例来说,A 网站和 B 网站是同一家公司的关联服务。现在要求,用户只要在其中一个网站登录,再访问另一个网站就会自动登录,请问怎么实现?

一种解决方案是 session 数据持久化,写入数据库或别的持久层。各种服务收到请求后,都向持久层请求数据。这种方案的优点是架构清晰,缺点是工程量比较大。另外,持久层万一挂了,就会单点失败。

另一种方案是服务器索性不保存 session 数据了,所有数据都保存在客户端,每次请求都发回服务器。JWT 就是这种方案的一个代表。抄自

4.2长什么样:

解码前和解码后:

左半部分是生成的token,右半部分是加密前的明文。分为三部分(左边的三种颜色,以.分隔):header,payload,verify signature。

下面依次介绍这三个部分。

4.2.1 Header

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

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

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

最后,将上面的 JSON 对象使用 Base64URL 算法(详见后文)转成字符串。

4.2.2 Payload

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

  • iss (issuer):签发人
  • exp (expiration time):过期时间
  • sub (subject):主题
  • aud (audience):受众
  • nbf (Not Before):生效时间
  • iat (Issued At):签发时间
  • jti (JWT ID):编号

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

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

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

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

4.2.3 Signature

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

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

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

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

4.2.4 Base64URL

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

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

抄自

5.注意事项:

(1)JWT 默认是不加密,但也是可以加密的。生成原始 Token 以后,可以用密钥再加密一次。

(2)JWT 不加密的情况下,不能将秘密数据写入 JWT。

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

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

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

(6)为了减少盗用,JWT 不应该使用 HTTP 协议明码传输,要使用 HTTPS 协议传输。抄自

5.1它是如何做身份验证的?

首先,JWT 的 Token 相当是明文,是可以解密的,任何存在 payload 的东西,都没有秘密可言,所以隐私数据不能签发 token。

而服务端,拿到 token 后解密,即可知道用户信息,例如本例中的uuid

有了 uuid,那么你就知道这个用户是谁,是否有权限进行下一步的操作。抄自:

5.2安全:

  1. 缩短 token 有效时间
  2. 使用安全系数高的加密算法
  3. token 不要放在 Cookie 中,有 CSRF 风险
  4. 使用 HTTPS 加密协议
  5. 对标准字段 iss、sub、aud、nbf、exp 进行校验
  6. 使用成熟的开源库,不要手贱造轮子
  7. 特殊场景下可以把用户的 UA、IP 放进 payload 进行校验(不推荐)

抄自:

5.3如何防止 Token 被串改?

此时 signature字段就是关键了,能被解密出明文的,只有headerpayload

假如黑客/中间人串改了payload,那么服务器可以通过signature去验证是否被篡改过。

在服务端在执行一次 signature = 加密算法(header + "." + payload, 密钥);, 然后对比 signature 是否一致,如果一致则说明没有被篡改。

所以为什么说服务器的密钥不能被泄漏。

如果泄漏,将存在以下风险:

  • 客户端可以自行签发 token
  • 黑客/中间人可以肆意篡改 token

抄自:

5.4jwt时效

jwt在有效时间内,都可以认证成功。这样则有可能会出现:

每次登陆都发一个jwt,但是这几次登陆发来的jwt都可以用。

对于多端登录每一端都会生成不同的jwt,所以不要在jwt中存储容易变化的信息。
对于用户注销登录后,之前的token仍然可以用。

如果想要设置只有一个jwt可用,或者是一端登录其他端自动失效,则需要配合数据库操作,将最新的jwt保存到数据库来验证或者是把想要失效的jwt保存到数据库中,验证jwt后再从数据库取出来验证有效性。

6.使用场景:

  • Authorization (授权) : 这是使用JWT的最常见场景。一旦用户登录,后续每个请求都将包含JWT,允许用户访问该令牌允许的路由、服务和资源。单点登录是现在广泛使用的JWT的一个特性,因为它的开销很小,并且可以轻松地跨域使用。
  • Information Exchange (信息交换) : 对于安全的在各方之间传输信息而言,JSON Web Tokens无疑是一种很好的方式。因为JWTs可以被签名,例如,用公钥/私钥对,你可以确定发送人就是它们所说的那个人。另外,由于签名是使用头和有效负载计算的,您还可以验证内容没有被篡改。

抄自:

7.怎么用?

客户端收到服务器返回的 JWT,可以储存在 Cookie 里面,也可以储存在 localStorage。

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

Authorization: Bearer 
 

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

 

java来说有两个常用的jwt库:

两个库用起来差不多,我平时用的是java-jwt,所以就以java-jwt来举例。

使用起来还是很简单的,看github中的介绍就可以用。推荐博客。

一般来说jwt编码和解码放到util工具包中,签名时使用统一的秘钥。但是我看其他博主(上面推荐的博客)也有使用用户个人密码来对jwt签名,并把jwt编码放到service来处理。

流程:

1.前端输入帐号密码请求后台接口,后台验证成功后颁发token:

 //使用该加密算法   Algorithm algorithm = Algorithm.HMAC256(SECRET);        JWTCreator.Builder builder = JWT.create()                .withIssuer(ISSUER) //设置发布者                .withExpiresAt(new Date(System.currentTimeMillis()+SHORT_TIME))//设置过期时间                .withClaim("userID",userID);//设置负载字段        return builder.sign(algorithm);//使用之前的加密算法生成token

2.前端在请求头中携带了此token,后台通过拦截器验证token

注意jwt会自动验证时间是否过期。

   

    Algorithm algorithm = null;        algorithm = Algorithm.HMAC256(SECRET);        log.debug("jwt验证access_token通过userid"+userID+"appid:"+appID);        JWTVerifier verifier = JWT.require(algorithm).withIssuer(ISSUER) .withClaim("userID",userID).build();        verifier.verify(token);

也可以不验证负载信息,而是获取负载信息:

     

  Algorithm algorithm = null;        algorithm = Algorithm.HMAC256(SECRET);        JWTVerifier verifier = JWT.require(algorithm).withIssuer(ISSUER) .build();        DecodedJWT jwt =  verifier.verify(token);        Map
map = jwt.getClaims();        return map.get("userID").asString();

其他参考文章:

8.个人理解:

对于一般的不带附加信息的接口,获取到了jwt,就可以访问此接口。

如果对于安全有强烈要求的话,可以要求接口上带上有关jwt封装时的信息:比如jwt颁发时在负载上加上了加密的受众字段 (audience),然后接口要求请求时带上此受众信息,在服务器中验证此带上的受众信息和jwt中的手中信息是否相同。

这样的情况下即使其他人获取了jwt,仍然不能通过此jwt来正常访问接口。

但是注意的是jwt要加密,如果使用的默认的base64,仍可以通过获取到的jwt,通过base64解密得到负载中的受众信息,然后在访问接口时带上此字段通过验证。

不过一般是没必要这样做的。

 

本篇文章还是抄袭文章,不过因为抄的太多了,设置为转载的时候不太方便,所以就厚着脸皮设置为原创文章。

你可能感兴趣的文章
HTML网页设计期末课程大作业~动漫樱桃小丸子5页表格div+css学生网页设计作业源码
查看>>
HTML学生网页设计作业成品~化妆品官方网站设计与实现(HTML+CSS+JS)共8个页面
查看>>
web课程设计网页规划与设计~在线阅读小说网页共6个页面(HTML+CSS+JavaScript+Bootstrap)
查看>>
HTML期末大作业~棋牌游戏静态网站(6个页面) HTML+CSS+JavaScript
查看>>
XmlValidationModeDetector源码分析
查看>>
解析 xml 为Document
查看>>
中国银行2013年校园招聘机试回忆录(综合部分专业题 考点)
查看>>
广发银行2013校园招聘笔试回忆录
查看>>
Android canvas rotate():平移旋转坐标系至任意原点任意角度-------附:android反三角函数小结...
查看>>
Matlab读取avi视频并播放 你必须要知道的
查看>>
word字体大小与公式编辑器字体对照表
查看>>
visio画图-----如何克服两箭头交叉变形 及 箭头自动重绘?
查看>>
Android开发:安装NDK,移植OpenCV2.3.1,JNI调用OpenCV全过程
查看>>
“金9银10”2020年JVM高频率面试题整理,技术提升就差一个点!
查看>>
简简单单的分享2020常见的MySQL面试题MySQL与答案整理
查看>>
听说只有大厂的Android工程师才能全答对这20道题?我看你在吹牛哦!
查看>>
武功秘籍之 Redis 面试题全掌握,学完马上找面试官对线!
查看>>
50道!2020年!!MySQL高频数据库面试题解析,你都懂了吗?
查看>>
如何用Spring Boot加密配置文件中的特殊内容示例代码详解
查看>>
谈谈这些年面试官给大伙下的那些套,如何解?(面试技巧)
查看>>