【应用安全】 使用Java创建和验证JWT
Java对JWT(JSON Web Tokens)的支持过去需要大量的工作:广泛的自定义,几小时的解析依赖关系,以及仅用于组装简单JWT的代码页。不再!
本教程将向您展示如何使用现有的JWT库来做两件事:
- 生成JWT
- 解码并验证JWT
您会注意到该教程非常简短。那是因为它很容易。如果您想深入挖掘,请查看JWT规范或深入了解有关在Spring Boot应用程序中使用JWT进行令牌身份验证的更长篇文章。
什么是JWT?
JSON Web令牌是用于以紧凑和安全的方式在各方之间发送信息的JSON对象。 JSON规范或Javascript Object Notation定义了一种使用键值对创建纯文本对象的方法。它是构建基于原始类型(数字,字符串等)的数据的紧凑方式。你可能已经非常熟悉JSON了。它就像没有所有括号的XML。
令牌可用于在各方之间发送任意状态。通常这里“聚会”表示客户端Web应用程序和服务器。 JWT有许多用途:身份验证机制,URL安全编码,安全共享私有数据,互操作性,数据到期等。
实际上,这些信息通常涉及两件事:授权和会话状态。服务器可以使用JWT告诉客户端应用程序允许用户执行哪些操作(或允许他们访问哪些数据)。
JWT通常还用于存储Web会话的依赖于状态的用户数据。因为JWT在客户端应用程序和服务器之间来回传递,这意味着状态数据不必存储在某个数据库中(并随后在每个请求中检索);因此,它可以很好地扩展。
让我们来看一个示例JWT(取自jsonwebtoken.io)
JWT有三个部分:标题,正文和签名。标题包含有关如何编码JWT的信息。身体是令牌的肉(声称存在的地方)。签名提供安全性。
关于如何编码令牌以及如何将信息存储在正文中,我们将不会详细介绍这些细节。如果需要,请查看前面提到的教程。
不要忘记:加密签名不提供机密性;它们只是一种检测篡改JWT的方法,除非JWT是专门加密的,否则它们是公开可见的。签名只是提供了一种验证内容的安全方法。
大。得到它了?现在你需要用JJWT制作一个令牌!在本教程中,我们使用的是现有的JWT库。 Java JWT(a.k.a.,JJWT)由Les Hazlewood创建(Apache Shiro的前任提交者,Stormpath的前联合创始人兼首席技术官,目前是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()方法执行以下操作:
- 设置散列算法
- 获取Issued At声明的当前日期
- 使用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异常。 如果签名匹配,则该方法将声明作为声明对象返回。
这就是它!
运行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
- 10种保护Spring Boot应用程序的绝佳方法
- 如果您的JWT被盗,会发生什么?
- JWT分析仪和Inspector Chrom插件
- 在线编码或解码JWT
本文:https://pub.intelligentx.net/application-security-create-and-validate-jwt-using-java
讨论:请加入知识星球或者小红圈【首席架构师圈】
- 63 次浏览