1.概述
REST API安全性中经常使用JSON Web令牌(JWT)。尽管可以通过诸如Spring Security OAuth之类的框架来解析令牌,但我们还是希望以自己的代码处理令牌。
在本教程中,我们将译码并验证JWT的完整性。
2. JWT令牌的结构
首先,让我们了解一下JWT令牌的结构:
- 标头
- payload (通常称为主体)
- 签名
签名是可选的。有效的JWT令牌只能由标头和有效负载部分组成。但是,我们使用签名部分来验证标头和有效负载中安全授权的内容。
这些部分表示为以句点(‘.')分隔的base64编码字符串。通过设计,任何人都可以译码JWT令牌并读取标头和有效负载部分的内容。但是,我们需要访问用于创建签名的密钥以验证令牌的完整性。
最常见的是,JWT包含用户的“声明”。这些代表有关用户的数据,API可以使用这些数据来授予权限或跟踪提供令牌的用户。译码令牌可以使应用程序使用数据,而验证则可以使应用程序相信JWT是由受信任的源生成的。
让我们看看如何在Java中译码和验证令牌。
3.译码JWT令牌
我们可以使用内置的Java函数译码令牌。
首先,让我们将令牌分为几个部分:
String[] chunks = token.split("\\.");
我们应该注意,传递给String.split
的正则表达式使用转义的'.'
避免使用'。'的字符。意思是“任何字符”。
我们的chunks
数组现在应该具有2或3个与JWT的部分相对应的元素。
接下来,让我们使用base64译码器对标头和有效负载部分进行译码:
Base64.Decoder decoder = Base64.getDecoder();
String header = new String(decoder.decode(chunks[0]));
String payload = new String(decoder.decode(chunks[1]));
让我们使用JWT令牌运行以下代码(我们可以在线译码以比较结果):
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkJhZWxkdW5nIFVzZXIiLCJpYXQiOjE1MTYyMzkwMjJ9.qH7Zj_m3kY69kxhaQXTa-ivIpytKXXjZc1ZSmapZnGE
输出将为我们提供译码后的标头任何有效载荷:
{"alg":"HS256","typ":"JWT"} {"sub":"1234567890","name":"Baeldung User","iat":1516239022}
如果仅在JWT令牌中定义了标头和有效载荷部分,那么我们就可以完成并成功译码信息。
4.验证JWT令牌
接下来,我们可以验证标头和有效负载的完整性,以确保没有通过使用签名部分来更改它们。
4.1 依赖关系
为了进行验证,我们可以将jjwt添加到我们的pom.xml
:
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.7.0</version>
</dependency>
我们应该注意,我们需要从版本0.7.0
开始的该库版本。
4.2 配置签名算法和密钥规范
要开始验证有效负载和报头,我们既需要使用最初用于对令牌进行签名的签名算法,也需要密钥:
SignatureAlgorithm sa = HS256;
SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes(), sa.getJcaName());
在此示例中,我们已将签名算法硬编码为HS256.
但是,我们可以译码标头的JSON并读取alg
字段以获取此值。
我们还应该注意,变量secretKey
是密钥的String表示形式。我们可以通过其配置或通过发布JWT的服务公开的REST API将其提供给我们的应用程序。
4.3 执行验证
现在我们有了签名算法和密钥,我们可以开始执行验证了。让我们将标头和有效负载重组到一个未签名的JWT中,并用“.”将它们连接起来。分隔符:
String tokenWithoutSignature = chunks[0] + "." + chunks[1];
String signature = chunks[2];
现在我们有了未签名的令牌和提供的签名。我们可以使用该库进行验证:
DefaultJwtSignatureValidator validator = new DefaultJwtSignatureValidator(sa, secretKeySpec);
if (!validator.isValid(tokenWithoutSignature, signature)) {
throw new Exception("Could not verify JWT token integrity!");
}
让我们分解一下。
首先,我们使用所选的算法和密码创建一个验证器。然后,我们为其提供未签名的令牌数据和所提供的签名。
然后。验证器将生成一个新签名,并将其与提供的签名进行比较。如果它们相等,那么我们已经验证了报头和有效载荷的完整性。
5.结论
在本教程中,我们研究了JWT的结构以及如何将其译码为JSON。
然后,我们使用一个库来使用其签名,算法和秘密密钥来验证令牌的完整性。
0 评论