Decode a JWT Token in Java – 在Java中对JWT令牌进行解码

最后修改: 2021年 3月 14日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

A JSON Web Token (JWT) is often used in REST API security. Even though the token can be parsed by frameworks such as Spring Security OAuth, we may want to process the token in our own code.

JSON Web Token(JWT)经常用于REST API安全。即使该令牌可以被诸如Spring Security OAuth等框架解析,我们也可能希望在自己的代码中处理该令牌。

In this tutorial, we’ll decode and verify the integrity of a JWT.

在本教程中,我们将对JWT进行解码并验证其完整性

2. Structure of a JWT

2.JWT的结构

First, let’s understand the structure of a JWT:

首先,让我们了解一下JWT的结构。

  • header
  • payload (often referred to as body)
  • signature

The signature is optional. A valid JWT can consist of just the header and payload sections. However, we use the signature section to verify the contents of the header and payload for security authorization.

签名是可选的。一个有效的JWT可以只由头和有效载荷部分组成。但是,我们使用签名部分来验证头和有效载荷的内容,以实现安全授权

Sections are represented as base64url-encoded strings separated by a period (‘.’) delimiter. By design, anyone can decode a JWT and read the contents of the header and payload sections. But we need access to the secret key used to create the signature to verify a token’s integrity.

各部分被表示为base64url编码的字符串,以句号(’.’)分隔。根据设计,任何人都可以解码JWT并读取头和有效载荷部分的内容。但我们需要访问用于创建签名的秘钥,以验证令牌的完整性。

Most commonly, the JWT contains a user’s “claims.” These represent data about the user, which the API can use to grant permissions or trace the user providing the token. Decoding the token allows the application to use the data, and validation allows the application to trust that the JWT was generated by a trusted source.

最常见的是,JWT包含一个用户的 “索赔”。这些代表了关于用户的数据,API可以用它来授予权限或追踪提供令牌的用户。解码令牌允许应用程序使用这些数据,而验证则允许应用程序相信JWT是由一个受信任的来源产生的。

Let’s look at how we can decode and validate a token in Java.

让我们来看看我们如何在Java中解码和验证一个令牌。

3. Decoding a JWT

3.解码JWT

We can decode a token using built-in Java functions.

我们可以使用内置的Java函数对令牌进行解码。

First, let’s split up the token into its sections:

首先,让我们把令牌分成几个部分。

String[] chunks = token.split("\\.");

We should note that the regular expression passed to String.split uses an escaped ‘.’ character to avoid ‘.’ meaning “any character.”

我们应该注意,传递给String.split的正则表达式使用了一个转义的‘.’字符,以避免’.’意味着 “任何字符”。

Our chunks array should now have two or three elements corresponding to the sections of the JWT.

我们的chunks数组现在应该有两个或三个元素与JWT的部分相对应。

Next, let’s decode the header and payload parts using a base64url decoder:

接下来,让我们使用base64url解码器对标题和有效载荷部分进行解码。

Base64.Decoder decoder = Base64.getUrlDecoder();

String header = new String(decoder.decode(chunks[0]));
String payload = new String(decoder.decode(chunks[1]));

Let’s run this code with a JWT (we can decode online to compare results):

让我们用JWT运行这段代码(我们可以在线解码来比较结果)。

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkJhZWxkdW5nIFVzZXIiLCJpYXQiOjE1MTYyMzkwMjJ9.qH7Zj_m3kY69kxhaQXTa-ivIpytKXXjZc1ZSmapZnGE

The output will give us the decoded header any payload:

输出将给我们解码的标题和有效载荷。

{"alg":"HS256","typ":"JWT"}{"sub":"1234567890","name":"Baeldung User","iat":1516239022}

If only the header and payload sections are defined in a JWT, we are finished and have the information decoded successfully.

如果在JWT中只定义了头和有效载荷部分,那么我们就完成了,并成功解码了信息。

4. Verifying JWT

4.验证JWT

Next, we can verify the integrity of the header and payload to ensure that they have not been altered by using the signature section.

接下来,我们可以通过使用签名部分来验证头和有效载荷的完整性,以确保它们没有被篡改。

4.1. Dependencies

4.1. 依赖性

For the verification, we can add jjwt to our pom.xml:

为了验证,我们可以在我们的pom.xml中添加jjwt>。

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.7.0</version>
</dependency>

We should note that we need a version of this library from version 0.7.0 onwards.

我们应该注意到,我们需要一个从0.7.0版本开始的这个库。

4.2. Configuring Signature Algorithm and Key Specification

4.2.配置签名算法和密钥规范

To begin verifying the payload and header, we need both the signature algorithm that was used originally to sign the token and the secret key:

为了开始验证有效载荷和标题,我们需要最初用于签署令牌的签名算法和秘密密钥。

SignatureAlgorithm sa = HS256;
SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes(), sa.getJcaName());

In this example, we’ve hard-coded our signature algorithm to HS256. However, we could decode the JSON of the header and read the alg field to get this value.

在这个例子中,我们将签名算法硬编码为HS256。然而,我们可以对头的JSON进行解码,并读取alg字段来获得这个值。

We should also note that the variable secretKey is a String representation of the secret key. We might provide this to our application via its configuration or via a REST API exposed by the service that issues the JWT.

我们还应该注意,变量secretKey是秘密密钥的字符串表示。我们可以通过配置或通过发布JWT的服务所暴露的REST API将其提供给我们的应用程序。

4.3. Performing the Verification

4.3.执行验证

Now that we have the signature algorithm and secret key, we can begin to perform the verification.

现在我们有了签名算法和秘钥,我们可以开始进行验证。

Let’s recombine the header and payload into an unsigned JWT, joining them with the ‘.’ delimiter:

让我们把头和有效载荷重新组合成一个无符号的JWT,用’.’分隔符连接它们。

String tokenWithoutSignature = chunks[0] + "." + chunks[1];
String signature = chunks[2];

Now we have the unsigned token and the provided signature. We can use the library to validate it:

现在我们有了无符号令牌和提供的签名。我们可以使用库来验证它。

DefaultJwtSignatureValidator validator = new DefaultJwtSignatureValidator(sa, secretKeySpec);

if (!validator.isValid(tokenWithoutSignature, signature)) {
    throw new Exception("Could not verify JWT token integrity!");
}

Let’s break this down.

让我们来分析一下这个问题。

First, we create a validator with the chosen algorithm and secret. Then we provide it the unsigned token data and the provided signature.

首先,我们用选定的算法和秘密创建一个验证器。然后,我们向它提供无符号的令牌数据和提供的签名。

Then the validator generates a fresh signature and compares it against the provided signature. If they are equal, we have verified the integrity of the header and payload.

然后验证器生成一个新的签名,并与提供的签名进行比较。如果它们相等,我们就已经验证了头和有效载荷的完整性。

5. Conclusion

5.总结

In this article, we looked at the structure of a JWT and how to decode it into JSON.

在这篇文章中,我们看了JWT的结构以及如何将其解码为JSON。

Then we used a library to verify the integrity of a token using its signature, algorithm and secret key.

然后,我们使用一个库来验证一个令牌的完整性,使用其签名、算法和秘密密钥。

As always, the code examples from this article can be found over on GitHub.

一如既往,本文中的代码示例可以在GitHub上找到over