该文主要带你了解什么是 JWT,以及JWT 定义和先关概念的介绍,并经过简单Demo 带你了解如何使用 SpringBoot 2 整合 JWT。
介绍前在这里咱们来探讨一下如何学习一门新的技术,我我的总结为 RSA。javascript
关于 RSA 仅仅代码我的的学习观点,只是给读者一个不成熟的小建议哈
官网介绍以下:html
What is JSON Web Token?
JSON Web Token (JWT) is an open standard ( RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed. JWTs can be signed using a secret (with the HMAC algorithm) or a public/private key pair using RSA or ECDSA.
Although JWTs can be encrypted to also provide secrecy between parties, we will focus on signed tokens. Signed tokens can verify the integrity of the claims contained within it, while encrypted tokens hide those claims from other parties. When tokens are signed using public/private key pairs, the signature also certifies that only the party holding the private key is the one that signed it.
中文翻译:
JSON Web令牌(JWT)是一个开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式,用于在各方之间做为JSON对象安全地传输信息。该信息能够被验证和信任,由于它是数字签名的。JWTS可使用秘密(使用HMAC算法)或公钥/私钥对使用RSA或ECDSA来签名。
虽然JWTS能够加密,但也提供保密各方之间,咱们将重点放在签名令牌。签名的令牌能够验证包含在其中的声明的完整性,而加密的令牌隐藏这些声明以防其余各方。当令牌使用公钥/私钥对签名时,签名也证实只有持有私钥的方才是签名的方。java
使用 JWT 前须要先了解三块内容:git
头部信息由2部分组成github
头部信息 JSON 代码以下:算法
{ "alg": "HS256", "typ": "JWT" }
而后,这个JSON被编码为 Base64Url,造成 JWT 的第一部分。spring
其中包含声明(claims),声明能够存放实体(一般是用户)和其余数据的声明,声明包括3种类型segmentfault
已注册声明
这些是一组预约义声明,不是强制性的,但建议使用,以提供一组有用的,可互操做的声明。其中一些是: iss(发行人), exp(到期时间),sub(主题), aud(观众)等安全
公开声明
能够参考 IANA JSON Web令牌注册表https://www.iana.org/assignme... 查看公共的声明springboot
私有声明
根据根据本身的业务须要自定义的一些数据格式。
示例有效负载能够是:
{ "sub": "1234567890", "name": "John Doe", "admin": true }
这个部分须要 base64 加密后的 头部信息(header) 和 base64 加密后的载荷信息(payload),使用链接组成的字符串,而后经过头部信息(header)中声明的加密方式进行加盐 secret 组合在加密,而后就构成了 JWT 的第三部分。
例如,若是要使用HMAC SHA256算法,将按如下方式建立签名:
HMACSHA256(base64UrlEncode(header) + "." +base64UrlEncode(payload),secret)
首先去 JWT 官网一探究竟,访问 https://jwt.io 进入 JWT 官网。接下来咱们开始学习若是使用JWT,经过点击上图中 LEARN MORE ABOUT JWT 显示以下图:而后点击START USING THE TOOL。
![图片]
![图片]
以下图所示 选择对应的语言的 JWT 使用教程。咱们这里介绍是是 标注有:maven:com.auth0 java-jwt 的版本。
查看 JWT GitHub 示例教程和源码。 https://github.com/auth0/java-jwt
在README.md 文件中有使用介绍和示例程序。
GitHub 上的示例相对简单些,接下来我带你们写一个相对详细的Demo。
第一步在SpringBoot 应用中引入JWT 依赖到pom.xml中
<dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>3.4.1</version> </dependency>
咱们经过三个方法来演示如何使用JWT
第一步:构建头部信息
Map<String, Object> map = new HashMap<String, Object>(); map.put("alg", "HS256"); map.put("typ", "JWT");
第二步:构建密钥信息
Algorithm algorithm = Algorithm.HMAC256("secret");
第三步:咱们经过定义注册和自定义声明 并组合头部信息和密钥信息生成jwt token
String token = JWT.create() .withHeader(map)// 设置头部信息 Header .withIssuer("SERVICE")//设置 载荷 签名是有谁生成 例如 服务器 .withSubject("this is test token")//设置 载荷 签名的主题 // .withNotBefore(new Date())//设置 载荷 定义在什么时间以前,该jwt都是不可用的. .withAudience("APP")//设置 载荷 签名的观众 也能够理解谁接受签名的 .withIssuedAt(nowDate) //设置 载荷 生成签名的时间 .withExpiresAt(expireDate)//设置 载荷 签名过时的时间 .sign(algorithm);//签名 Signature
详细代码以下:
@Test public void createToken() { String secret = "secret";// token 密钥 Algorithm algorithm = Algorithm.HMAC256("secret"); // 头部信息 Map<String, Object> map = new HashMap<String, Object>(); map.put("alg", "HS256"); map.put("typ", "JWT"); Date nowDate = new Date(); Date expireDate = getAfterDate(nowDate, 0, 0, 0, 2, 0, 0);// 2小过时 String token = JWT.create() .withHeader(map)// 设置头部信息 Header .withIssuer("SERVICE")//设置 载荷 签名是有谁生成 例如 服务器 .withSubject("this is test token")//设置 载荷 签名的主题 // .withNotBefore(new Date())//设置 载荷 定义在什么时间以前,该jwt都是不可用的. .withAudience("APP")//设置 载荷 签名的观众 也能够理解谁接受签名的 .withIssuedAt(nowDate) //设置 载荷 生成签名的时间 .withExpiresAt(expireDate)//设置 载荷 签名过时的时间 .sign(algorithm);//签名 Signature Assert.assertTrue(token.length() > 0); }
自定义信息经过 withClaim 方法进行添加,具体操做以下:
JWT.create() .withHeader(map) .withClaim("loginName", "zhuoqianmingyue") .withClaim("userName", "张三") .withClaim("deptName", "技术部")
生成携带自定义信息 JWT token 详细代码以下:
@Test public String createTokenWithChineseClaim() { Date nowDate = new Date(); Date expireDate = getAfterDate(nowDate, 0, 0, 0, 2, 0, 0);// 2小过时 Map<String, Object> map = new HashMap<String, Object>(); map.put("alg", "HS256"); map.put("typ", "JWT"); Algorithm algorithm = Algorithm.HMAC256("secret"); String token = JWT.create().withHeader(map) /* 设置 载荷 Payload */ .withClaim("loginName", "zhuoqianmingyue").withClaim("userName", "张三").withClaim("deptName", "技术部") .withIssuer("SERVICE")// 签名是有谁生成 例如 服务器 .withSubject("this is test token")// 签名的主题 // .withNotBefore(new Date())//定义在什么时间以前,该jwt都是不可用的 .withAudience("APP")// 签名的观众 也能够理解谁接受签名的 .withIssuedAt(nowDate) // 生成签名的时间 .withExpiresAt(expireDate)// 签名过时的时间 /* 签名 Signature */ .sign(algorithm); Assert.assertTrue(token.length() > 0); return token;
第一步:构建密钥信息
Algorithm algorithm = Algorithm.HMAC256("secret");
第二步:经过密钥信息和签名的发布者的信息生成JWTVerifier (JWT验证类)
JWTVerifier verifier = JWT.require(algorithm) .withIssuer("SERVICE") .build(); Algorithm algorithm = Algorithm.HMAC256("secret");
不添加 .withIssuer("SERVICE") 也是能够获取 JWTVerifier 。
第三步:经过JWTVerifier 的verify获取 token中的信息。
DecodedJWT jwt = verifier.verify(token);
以下面代码所示就能够获取到咱们以前生成 token 的 签名的主题,观众 和自定义的声明信息。
String subject = jwt.getSubject(); List<String> audience = jwt.getAudience(); Map<String, Claim> claims = jwt.getClaims(); for (Entry<String, Claim> entry : claims.entrySet()) { String key = entry.getKey(); Claim claim = entry.getValue(); System.out.println("key:"+key+" value:"+claim.asString()); }
验证 JWT Token 详细代码以下:
@Test public void verifyToken() throws UnsupportedEncodingException { String token = createTokenWithChineseClaim2(); Algorithm algorithm = Algorithm.HMAC256("secret"); JWTVerifier verifier = JWT.require(algorithm).withIssuer("SERVICE").build(); // Reusable verifier instance DecodedJWT jwt = verifier.verify(token); String subject = jwt.getSubject(); List<String> audience = jwt.getAudience(); Map<String, Claim> claims = jwt.getClaims(); for (Entry<String, Claim> entry : claims.entrySet()) { String key = entry.getKey(); Claim claim = entry.getValue(); log.info("key:" + key + " value:" + claim.asString()); } Claim claim = claims.get("loginName"); log.info(claim.asString()); log.info(subject); log.info(audience.get(0)); } public String createTokenWithChineseClaim2() throws UnsupportedEncodingException { Date nowDate = new Date(); Date expireDate = getAfterDate(nowDate, 0, 0, 0, 2, 0, 0);// 2小过时 Map<String, Object> map = new HashMap<String, Object>(); map.put("alg", "HS256"); map.put("typ", "JWT"); User user = new User(); user.setUserNaem("张三"); user.setDeptName("技术部"); Gson gson = new Gson(); String userJson = gson.toJson(user); String userJsonBase64 = BaseEncoding.base64().encode(userJson.getBytes()); Algorithm algorithm = Algorithm.HMAC256("secret"); String token = JWT.create().withHeader(map) .withClaim("loginName", "zhuoqianmingyue").withClaim("user", userJsonBase64).withIssuer("SERVICE")// 签名是有谁生成 .withSubject("this is test token")// 签名的主题 // .withNotBefore(new Date())//该jwt都是不可用的时间 .withAudience("APP")// 签名的观众 也能够理解谁接受签名的 .withIssuedAt(nowDate) // 生成签名的时间 .withExpiresAt(expireDate)// 签名过时的时间 .sign(algorithm);//签名 Signature return token; }
JWT 就是一个生成 Token 的工具,若是不使用 JWT 咱们也能够根据本身加密规则生成 Token。只不过 JWT 规范了生成 Token 定义了一个标准而已。JWT 的核心的功能就是:生成Token、解析Token。在 玩转 SpringBoot 2 之整合 JWT 下篇中将带你们经过一个接口登陆的案例简单介绍 JWT 实战操做。
具体代码示例请查看个人GitHub 仓库 springbootexamples 中的 spring-boot-2.x-jwt 下 src/test/java JWTDemo.java文件。
GitHub:https://github.com/zhuoqianmi...
https://jwt.io/introduction/
https://github.com/auth0/java...