“我喜欢编写身份验证和授权代码。” 〜从来没有Java开发人员。 厌倦了一次又一次地建立相同的登录屏幕? 尝试使用Okta API进行托管身份验证,授权和多因素身份验证。
Java对JWT(JSON Web令牌)的支持过去需要进行大量工作:广泛的自定义,花费数小时来解决依赖项,以及仅用于组装简单JWT的代码页。 不再!
本教程将向您展示如何使用现有的JWT库做两件事:
- 生成一个JWT
- 解码并验证JWT
您会注意到本教程很短。 那是因为那很容易。 如果您想更深入地了解,请查看JWT规范或深入阅读有关在Spring Boot应用程序中使用JWT进行令牌身份验证的更长的文章 。
什么是JWT?
JSON Web令牌是JSON对象,用于在各方之间以紧凑和安全的方式发送信息。 JSON规范 (或Javascript对象表示法)定义了一种使用键值对创建纯文本对象的方法。 这是一种构造基于原始类型(数字,字符串等)的数据的紧凑方法。 您可能已经非常熟悉JSON。 就像没有括号的XML。
令牌可用于在各方之间发送任意状态。 这里的“当事人”通常是指客户端Web应用程序和服务器。 JWT具有多种用途:身份验证机制,URL安全编码,安全共享私有数据,互操作性,数据过期等。
实际上,此信息通常与两件事有关:授权和会话状态。 服务器可以使用JWT告诉客户端应用程序允许用户执行哪些操作(或允许他们访问哪些数据)。
JWT通常还用于存储Web会话的状态相关用户数据。 因为JWT是在客户端应用程序和服务器之间来回传递的,这意味着状态数据不必存储在某个地方的数据库中(随后在每个请求中都可以检索到); 因此,它可以很好地扩展。
让我们看一个JWT示例(取自jsonwebtoken.io )
![Java中的JWT](https://i-blog.csdnimg.cn/blog_migrate/daf63ee078a7a7047c4c76bda2ff7499.png)
JWT具有三部分:标头,正文和签名。 标头包含有关JWT编码方式的信息。 主体是代币的肉 ( 索赔所在的地方)。 签名提供了安全性。
关于令牌的编码方式以及信息在体内的存储方式,我们这里不做很多详细介绍。 如果需要,请查看前面提到的教程 。
不要忘记:加密签名不提供保密性; 它们只是检测篡改JWT的一种方式,除非JWT经过专门加密,否则它们是公开可见的。 签名只是提供了一种验证内容的安全方法。
大。 得到它了? 现在,您需要使用JJWT制作令牌! 对于本教程,我们使用现有的JWT库。 Java JWT (又名JJWT)是由Les Hazlewood (Apache Shiro的主要提交人,Apache Shiro是Stormpath的前联合创始人兼CTO,现在是Okta自己的高级架构师)创建的,JJWT是一个简化JWT创建和验证的Java库。 它完全基于JWT , JWS , JWE , JWK和JWA RFC规范,并根据Apache 2.0许可的条款开源。 该库还为规范添加了一些不错的功能,例如JWT压缩和声明执行。
用Java生成令牌
这部分超级容易。 让我们看一些代码。 克隆GitHub存储库 :
git clone https://github.com/oktadeveloper/okta-java-jwt-example.git
cd okta-java-jwt-example
这个示例非常基础,并且包含一个src/main/java/JWTDemo.java
类文件,其中包含两个静态方法: createJWT()
和decodeJWT()
。 足够巧妙的是,这两种方法创建了一个JWT并对JWT进行解码。 看下面的第一种方法。
public static String createJWT(String id, String issuer, String subject, long ttlMillis) {
//The JWT signature algorithm we will be using to sign the token
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
long nowMillis = System.currentTimeMillis();
Date now = new Date(nowMillis);
//We will sign our JWT with our ApiKey secret
byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(SECRET_KEY);
Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());
//Let's set the JWT Claims
JwtBuilder builder = Jwts.builder().setId(id)
.setIssuedAt(now)
.setSubject(subject)
.setIssuer(issuer)
.signWith(signatureAlgorithm, signingKey);
//if it has been specified, let's add the expiration
if (ttlMillis > 0) {
long expMillis = nowMillis + ttlMillis;
Date exp = new Date(expMillis);
builder.setExpiration(exp);
}
//Builds the JWT and serializes it to a compact, URL-safe string
return builder.compact();
}
总而言之, createJWT()
方法执行以下操作:
- 设置哈希算法
- 获取签发日期索赔的当前日期
- 使用SECRET_KEY静态属性生成签名密钥
- 使用流畅的API添加声明并签署JWT
- 设置到期日期
可以根据您的需求进行定制。 例如,如果您想添加其他或自定义声明。
解码令牌
现在看一下更简单的decodeJWT()
方法。
public static Claims decodeJWT(String jwt) {
//This line will throw an exception if it is not a signed JWS (as expected)
Claims claims = Jwts.parser()
.setSigningKey(DatatypeConverter.parseBase64Binary(SECRET_KEY))
.parseClaimsJws(jwt).getBody();
return claims;
}
该方法再次使用静态SECRET_KEY
属性生成签名密钥,并使用该方法来验证JWT是否未被篡改。 如果签名与令牌不匹配,则该方法将引发io.jsonwebtoken.SignatureException
异常。 如果签名确实匹配,则该方法将索赔作为Claims
对象返回。
差不多了!
运行JUnit测试
为了获得更多的荣誉,您可以在示例项目中运行JUnit测试。 有三个测试,它们演示了JJWT库的一些基本功能。 第一个测试显示了一条愉快的路,创建并成功解码了有效的JWT。 第二个测试显示了当您尝试将完全伪造的字符串解码为JWT时,JJWT库将如何失败。 最后一个测试显示了被JJWT篡改的方式将如何导致decodeJWT()
方法引发SignatureException
。
您可以使用以下命令从命令行运行这些测试:
./gradlew test -i
-i
将Gradle的日志级别设置为Info
以便我们看到测试的简单日志输出。
了解有关在Java应用程序中使用JWT的更多信息
JJWT库使创建和验证JWT非常容易。 只需指定一个秘密密钥和一些声明,您就会拥有一个JJWT。 以后,使用相同的密钥对JJWT进行解码并验证其内容。
现在,创建和使用JJWT非常简单,为什么不使用它们呢?
不要忘记SSL! 请记住,除非对JWT进行加密,否则它们中编码的信息通常仅是Base64编码的,任何小孩和一些宠物都可以读取。 因此,除非您希望中国,俄罗斯和FBI读取所有会话数据,否则请使用SSL对其进行加密。
Baeldung 在Java和JWT上有相当不错的深入教程 。
另外,这里还有Okta博客提供的更多链接,可帮助您继续前进:
- Java应用程序的简单令牌认证
- Spring Boot,OAuth 2.0和Okta入门
- 确保Spring Boot应用程序安全的10种绝佳方法
- 如果您的JWT被盗怎么办?
- JWT分析器和检查器Chrom插件
- 在线编码或解码JWT
如果您对此帖子有任何疑问,请在下面添加评论。 有关更多精彩内容, 请在Twitter上关注@oktadev , 在Facebook上关注我们,或订阅我们的YouTube频道 。
“我喜欢编写身份验证和授权代码。” 〜从来没有Java开发人员。 厌倦了一次又一次地建立相同的登录屏幕? 尝试使用Okta API进行托管身份验证,授权和多因素身份验证。
``教程:用Java创建和验证JWT''最初于2018年10月31日发布在Okta开发者博客上。
翻译自: https://www.javacodegeeks.com/2019/01/tutorial-create-verify-jwts-java.html