相信网络上面讲解JWT是什么,由什么组成的文章已经很多了,本文主要讲解JWT在Java中的使用,为了初次看到JWT的同学不会一脸懵逼,还是会说一下什么是JWT.
本文主要从以下几个方面说

什么是JWT和JWT的组成

为什么要使用JWT

在Java中如何使用JWT

1.什么是JWT

Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。

2.JWT有什么好处?

1、支持跨域访问: Cookie是不允许垮域访问的,这一点对Token机制是不存在的,前提是传输的用户认证信息通过HTTP头传输.

2、无状态(也称:服务端可扩展行):Token机制在服务端不需要存储session信息,因为Token 自身包含了所有登录用户的信息,只需要在客户端的cookie或本地介质存储状态信息.

4、更适用CDN: 可以通过内容分发网络请求你服务端的所有资料(如:javascript,HTML,图片等),而你的服务端只要提供API即可.(居于前面两点得出这个更适用于CDN内容分发网络)

5、去耦: 不需要绑定到一个特定的身份验证方案。Token可以在任何地方生成,只要在你的API被调用的时候,你可以进行Token生成调用即可.(这个似乎也在继续说前面第一点和第二点的好处。。。)

6、更适用于移动应用: 当你的客户端是一个原生平台(iOS, Android,Windows 8等)时,Cookie是不被支持的(你需要通过Cookie容器进行处理),这时采用Token认证机制就会简单得多。

7、CSRF:因为不再依赖于Cookie,所以你就不需要考虑对CSRF(跨站请求伪造)的防范。(如果token是用cookie保存,CSRF还是需要考虑,一般建议使用1、在HTTP请求中以参数的形式加入一个服务器端产生的token。或者2.放入http请求头中也就是一次性给所有该类请求加上csrftoken这个HTTP头属性,并把token值放入其中)
ps:后面会推出一些常见的网络安全的处理

8、性能: 一次网络往返时间(通过数据库查询session信息)总比做一次HMACSHA256计算 的Token验证和解析要费时得多.

9、不需要为登录页面做特殊处理: 如果你使用Protractor 做功能测试的时候,不再需要为登录页面做特殊处理.(知识面太窄,不是太明白这个的意思)

10、基于标准化:你的API可以采用标准化的 JSON Web Token (JWT). 这个标准已经存在多个后端库(.NET, Ruby, Java,Python, PHP)和多家公司的支持(如:Firebase,Google, Microsoft).

JWT的组成

第一部分我们称它为头部(header),第二部分我们称其为载荷(payload, 类似于飞机上承载的物品),第三部分是签证(signature).

header

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

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

完整的头部就像下面这样的JSON:

{'typ': 'JWT','alg': 'HS256'
}
  • 1
  • 2
  • 3
  • 4

然后将头部进行base64加密(该加密是可以对称解密的),构成了第一部分.

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
  • 1

playload

载荷就是存放有效信息的地方。这个名字像是特指飞机上承载的货品,这些有效信息包含三个部分

标准中注册的声明
公共的声明
私有的声明
  • 1
  • 2
  • 3
  • 4

==标准==中注册的声明 (==建议但不强制使用==) :

iss: jwt签发者
sub: jwt所面向的用户
aud: 接收jwt的一方
exp: jwt的过期时间,这个过期时间必须要大于签发时间
nbf: 定义在什么时间之前,该jwt都是不可用的.
iat: jwt的签发时间
jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

==公共==的声明 :
公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息.但不建议添加敏感信息,因为该部分在客户端可解密.

==私有==的声明 :
私有声明是提供者和消费者所共同定义的声明,一般不建议存放敏感信息,因为base64是对称解密的,意味着该部分信息可以归类为明文信息。

这个指的就是自定义的claim。比如前面那个结构举例中的admin和name都属于自定的claim。这些claim跟JWT标准规定的claim区别在于:JWT规定的claim,JWT的接收方在拿到JWT之后,都知道怎么对这些标准的claim进行验证(还不知道是否能够验证);而private claims不会验证,除非明确告诉接收方要对这些claim进行验证以及规则才行。

定义一个payload:

{"sub": "1234567890","name": "John Doe","admin": true
}
  • 1
  • 2
  • 3
  • 4
  • 5

然后将其进行base64加密,得到Jwt的第二部分。

eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9
  • 1

signature

jwt的第三部分是一个签证信息,这个签证信息由三部分组成:

header (base64后的)
payload (base64后的)
secret
  • 1
  • 2
  • 3
  • 4

这个部分需要base64加密后的header和base64加密后的payload使用.连接组成的字符串,然后通过header中声明的加密方式进行加盐secret组合加密,然后就构成了jwt的第三部分。

// javascript
var encodedString = base64UrlEncode(header) + '.' + base64UrlEncode(payload);var signature = HMACSHA256(encodedString, 'secret'); // TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
  • 1
  • 2
  • 3
  • 4

将这三部分用.连接成一个完整的字符串,构成了最终的jwt:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
  • 1

注意:secret是保存在服务器端的,jwt的签发生成也是在服务器端的,secret就是用来进行jwt的签发和jwt的验证,所以,它就是你服务端的私钥,在任何场景都不应该流露出去。一旦客户端得知这个secret, 那就意味着客户端是可以自我签发jwt了。

JWT如何应用(目前就这两种适用、当然还可以将token添加到cookie中,但是不建议使用)

在请求地址中添加token并验证

CSRF攻击之所以能够成功,是因为攻击者可以伪造用户的请求,该请求中所有的用户验证信息都存在于Cookie中,因此攻击者可以在不知道这些验证信息的情况下直接利用用户自己的Cookie来通过安全验证。由此可知,抵御CSRF攻击的关键在于:在请求中放入攻击者所不能伪造的信息,并且该信息不存在于Cookie之中。鉴于此,系统开发者可以在HTTP请求中以参数的形式加入一个随机产生的token,并在服务器端建立一个拦截器来验证这个token,如果请求中没有token或者token内容不正确,则认为可能是CSRF攻击而拒绝该请求。

在HTTP头中自定义属性并验证

自定义属性的方法也是使用token并进行验证,和前一种方法不同的是,这里并不是把token以参数的形式置于HTTP请求之中,而是把它放到HTTP头中自定义的属性里。通过XMLHttpRequest这个类,可以一次性给所有该类请求加上csrftoken这个HTTP头属性,并把token值放入其中。这样解决了前一种方法在请求中加入token的不便,同时,通过这个类请求的地址不会被记录到浏览器的地址栏,也不用担心token会通过Referer泄露到其他网站。

Java的JJWT实现JWT

创建jwt:

本文主要使用的是jjwt-0.6.0.jar

jar包下载地址

JJWT的github地址

/*** 创建jwt* @param id* @param subject* @param ttlMillis 过期的时间长度* @return* @throws Exception*/public String createJWT(String id, String subject, long ttlMillis) throws Exception {SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256; //指定签名的时候使用的签名算法,也就是header那部分,jjwt已经将这部分内容封装好了。long nowMillis = System.currentTimeMillis();//生成JWT的时间Date now = new Date(nowMillis);Map<String,Object> claims = new HashMap<String,Object>();//创建payload的私有声明(根据特定的业务需要添加,如果要拿这个做验证,一般是需要和jwt的接收方提前沟通好验证方式的)claims.put("uid", "DSSFAWDWADAS...");claims.put("user_name", "admin");claims.put("nick_name","DASDA121");SecretKey key = generalKey();//生成签名的时候使用的秘钥secret,这个方法本地封装了的,一般可以从本地配置文件中读取,切记这个秘钥不能外露哦。它就是你服务端的私钥,在任何场景都不应该流露出去。一旦客户端得知这个secret, 那就意味着客户端是可以自我签发jwt了。//下面就是在为payload添加各种标准声明和私有声明了JwtBuilder builder = Jwts.builder() //这里其实就是new一个JwtBuilder,设置jwt的body.setClaims(claims)          //如果有私有声明,一定要先设置这个自己创建的私有的声明,这个是给builder的claim赋值,一旦写在标准的声明赋值之后,就是覆盖了那些标准的声明的.setId(id)                  //设置jti(JWT ID):是JWT的唯一标识,根据业务需要,这个可以设置为一个不重复的值,主要用来作为一次性token,从而回避重放攻击。.setIssuedAt(now)           //iat: jwt的签发时间.setSubject(subject)        //sub(Subject):代表这个JWT的主体,即它的所有人,这个是一个json格式的字符串,可以存放什么userid,roldid之类的,作为什么用户的唯一标志。.signWith(signatureAlgorithm, key);//设置签名使用的签名算法和签名使用的秘钥if (ttlMillis >= 0) {long expMillis = nowMillis + ttlMillis;Date exp = new Date(expMillis);builder.setExpiration(exp);     //设置过期时间}return builder.compact();           //就开始压缩为xxxxxxxxxxxxxx.xxxxxxxxxxxxxxx.xxxxxxxxxxxxx这样的jwt//打印了一哈哈确实是下面的这个样子//eyJhbGciOiJIUzI1NiJ9.eyJ1aWQiOiJEU1NGQVdEV0FEQVMuLi4iLCJzdWIiOiIiLCJ1c2VyX25hbWUiOiJhZG1pbiIsIm5pY2tfbmFtZSI6IkRBU0RBMTIxIiwiZXhwIjoxNTE3ODI4MDE4LCJpYXQiOjE1MTc4Mjc5NTgsImp0aSI6Imp3dCJ9.xjIvBbdPbEMBMurmwW6IzBkS3MPwicbqQa2Y5hjHSyo}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
解析jwt
/*** 解密jwt* @param jwt* @return* @throws Exception*/public Claims parseJWT(String jwt) throws Exception{SecretKey key = generalKey();  //签名秘钥,和生成的签名的秘钥一模一样Claims claims = Jwts.parser()  //得到DefaultJwtParser.setSigningKey(key)         //设置签名的秘钥.parseClaimsJws(jwt).getBody();//设置需要解析的jwtreturn claims;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
上面代码中两次用到的generalKey()方法
/*** 由字符串生成加密key* @return*/public SecretKey generalKey(){String stringKey = Constant.JWT_SECRET;//本地配置文件中加密的密文7786df7fc3a34e26a61c034d5ec8245dbyte[] encodedKey = Base64.decodeBase64(stringKey);//本地的密码解码[B@152f6e2System.out.println(encodedKey);//[B@152f6e2System.out.println(Base64.encodeBase64URLSafeString(encodedKey));//7786df7fc3a34e26a61c034d5ec8245dSecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");// 根据给定的字节数组使用AES加密算法构造一个密钥,使用 encodedKey中的始于且包含 0 到前 leng 个字节这是当然是所有。(后面的文章中马上回推出讲解Java加密和解密的一些算法)return key;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
main方法测试
    public static void main(String[] args) throws Exception {JwtUtil util=   new JwtUtil();String ab=util.createJWT("jwt", "{id:100,name:xiaohong}", 60000);System.out.println(ab);//eyJhbGciOiJIUzI1NiJ9.eyJ1aWQiOiJEU1NGQVdEV0FEQVMuLi4iLCJzdWIiOiJ7aWQ6MTAwLG5hbWU6eGlhb2hvbmd9IiwidXNlcl9uYW1lIjoiYWRtaW4iLCJuaWNrX25hbWUiOiJEQVNEQTEyMSIsImV4cCI6MTUxNzgzNTE0NiwiaWF0IjoxNTE3ODM1MDg2LCJqdGkiOiJqd3QifQ.ncVrqdXeiCfrB9v6BulDRWUDDdROB7f-_Hg5N0po980String jwt="eyJhbGciOiJIUzI1NiJ9.eyJ1aWQiOiJEU1NGQVdEV0FEQVMuLi4iLCJzdWIiOiJ7aWQ6MTAwLG5hbWU6eGlhb2hvbmd9IiwidXNlcl9uYW1lIjoiYWRtaW4iLCJuaWNrX25hbWUiOiJEQVNEQTEyMSIsImV4cCI6MTUxNzgzNTEwOSwiaWF0IjoxNTE3ODM1MDQ5LCJqdGkiOiJqd3QifQ.G_ovXAVTlB4WcyD693VxRRjOxa4W5Z-fklOp_iHj3Fg";Claims c=util.parseJWT(jwt);//注意:如果jwt已经过期了,这里会抛出jwt过期异常。System.out.println(c.getId());//jwtSystem.out.println(c.getIssuedAt());//Mon Feb 05 20:50:49 CST 2018System.out.println(c.getSubject());//{id:100,name:xiaohong}System.out.println(c.getIssuer());//nullSystem.out.println(c.get("uid", String.class));//DSSFAWDWADAS...}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

**关于Java的jwt的使用,目前了解到的知识尚浅,只是停留在表面,创建和解析jwt上面文章都说得很清楚,至于如何运用,这个需要根据具体的业务了,,,,,希望大家指出不足之处。。
上面文章也是看了很多篇文章,然后结合自己写得呆萌写出的,肯定有许多不足,希望各位大虾批评指正。**

JWT的Java使用 (JJWT)相关推荐

  1. JWT的学习和JJWT的使用

    1.什么是JWT JWT(JSON Web Token)是一个开放的行业标准,它定义了一种简介的,自包含的协议格式,用于在通信双方传递json对象,传递的信息经过数字签名可以被验证和信任.JWT可以使 ...

  2. java jwidnow_Web安全通讯之JWT的Java实现

    上篇文章中目的是介绍 Json Web Token(以下简称 jwt) ,由于我对 Java 比较熟悉就介绍 Java 服务端 的实现方式,其他语言原理是相同的哈~ 下面按照这几个方面来介绍它: Ja ...

  3. JWT|概述|JWT结构|JWT在java中的使用|JWT工具类的封装|JWT在springboot中的使用|JWT与拦截器的配合

    JWT ! 前记: 官网:https://jwt.io/ jwt有人说是用计算力换空间(相对于session) 小程序后台要求全部用springboot实现..登录状态的管理:本来想用自己随便生成UU ...

  4. Java用JJWT实现JWT

    JWT编码分为三部分,前两部分是base64编码,第三段是加密字符串. Maven <dependency><groupId>io.jsonwebtoken</group ...

  5. Web安全通讯之JWT的Java实现

    上篇文章中目的是介绍 Json Web Token(以下简称 jwt) ,由于我对 Java 比较熟悉就介绍 Java 服务端 的实现方式,其他语言原理是相同的哈~ PS:如果不清楚JWT,请先看 & ...

  6. JWT的讲解以及JJWT的使用(另附JWT工具类)

    0. 前言 关于JWT的文章网上已经多如牛毛了,但是相信很多同学学的还是云里雾里,所以在我学习JWT之后尽量用最简洁的描述写下这篇文章用于日后复习,与此同时也希望可以帮助同学们共同进步,如果文章对你有 ...

  7. JWT详解、JJWT使用、token 令牌

    前言 在正式讲解JWT之前,我们先重温一下用户身份认证相关的一些概念: 有状态登录(session认证) 服务器当中记录每一次的登录信息,从而根据客户端发送的数据来判断登录过来的用户是否合法. 缺点: ...

  8. Android 解析jwt遇到java.lang.IllegalArgumentException: bad base-64

    解析jwt的时候遇到了java.lang.IllegalArgumentException: bad base-64 百思不得其解 按照网上说的:Android&ios java 这俩咋就不好 ...

  9. web安全通信之JWT简介

    jwt简介 JWT是JSON Web Token的简称,它是一个非常轻巧的规范.这个规范允许我们使用JWT在用户和服务器之间传递安全可靠的信息. 和Cookie-Session的模式不同,JWT使用T ...

  10. JWT的基于JJWT在Java中使用

    1.什么是JWT Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式 ...

最新文章

  1. Sub-process /usr/bin/dpkg returned an error code (1) 如何解决
  2. 93. 复原 IP 地址(回溯算法)
  3. Sublime Text 3 import Anaconda 无法正常补全模块名解决办法
  4. float型y取值在1.0c语言表达式,2011年全国计算机二级C语言模拟试题及答案(14)...
  5. 2021年中国药店创新趋势报告
  6. MNIST机器学习入门(二)
  7. 【学习】DataFrameSeries类【pandas】
  8. 16套51单片机开发板资料共享下载,拼命整理
  9. Win7 AERO主题变成灰色解决方法
  10. 创建新的apple id_新的Apple Maps与Google Maps:哪个适合您?
  11. 快速搞懂MD5解密原理,了解常用的MD5在线解密网站
  12. 计算机的学情分析报告,计算机教学计划合集总结5篇
  13. p图软件pⅰc_pic修图软件下载-pic修图 安卓版v16.4.52-PC6安卓网
  14. Python物流运输管理系统源代码,基于Django实现,实现了运单录入、发车出库、到货签收、客户签收等基本功能,含测试账号
  15. Java面试题大全(2021版)
  16. 线上支付,出款和收款
  17. c++中find函数解析
  18. 文件系统/var空间100%的问题
  19. PlayerMaker小球随机弹跳练习
  20. asp毕业设计——基于asp+sqlserver的教学互动管理系统设计与实现(毕业论文+程序源码)——教学互动管理系统

热门文章

  1. 文件读入简单操作(C#)
  2. 【转】2011年考研备战时间表
  3. 一个计算周次和本周时间范围的代码(c#)
  4. 汪洋大海中的一块绿地
  5. 使用Nginx实现负载均衡
  6. centos7 vsftpd默认端口修改
  7. Hibernate(5)—— 联合主键 、一对一关联关系映射(xml和注解) 和 领域驱动设计...
  8. 如何选择和部署长尾关键词
  9. $().index() 两种用法
  10. 智能电视也需“杀毒”