大家好,欢迎来到IT知识分享网。
JWT(JSON Web Token)原理
- 1 JWT(JSON Web Token)介绍
- 1.2 JWT的组成
- 1.3 生成 JWT(Token)的流程
- 1.4 验证 JWT 的流程
- 1.5 JWT使用场景
- 2 JJWT——JWT的实现之一
- 2.1 JJWT的基本使用
- 2.1.1 生成JWT
- 2.1.2 解析和验证JWT
- 3 总结
1 JWT(JSON Web Token)介绍
JWT(JSON Web Token)是一种开放标准(RFC7519),用于在网络应用环境中安全地传递信息。它的设计目的是紧凑且安全,特别适合于分布式站点的单点登录(SSO)场景。JWT通常用于身份验证和信息交换,能够有效地在身份提供者和服务提供者之间传递认证用户的信息,以便访问资源服务器。
1.2 JWT的组成
JWT由三部分组成,分别是Header、Payload、Signature。
Header(头部):包含令牌的元数据,通常包括签名算法(alg)和类型(type)。例如:
{ "alg": "HS256", "typ": "JWT" }
这个 JSON 对象会经过 Base64Url 编码,成为 JWT 的第一部分。
Payload(载荷):存放实际需要传递的数据,可以包含一些官方标准声明如iss(签发人)、exp(过期时间)、sub(主题)等,也可以包含自定义字段。注意,载荷部分的数据是未加密的,因此不能包含敏感数据。
{ "sub": "", "name": "John Doe", "admin": true }
这些信息也是 JSON 对象,经过 Base64Url 编码后构成 JWT 的第二部分。
Signature(签名):签名是通过对头部和载荷使用指定的签名算法和密钥来计算的。例如,对于HS256算法,会使用一个密钥对头部和载荷的组合进行HMAC-SHA256计算得到签名。它用于验证消息在传递过程中没有被篡改,并且还可以验证发送者的身份(如果密钥是保密的)。
String signature = HMACSHA256(encodedString, secret);
这三部分通过.连接形成最终的JWT字符串,如:header.payload.signature。
1.3 生成 JWT(Token)的流程
步骤一:构建头部和载荷
首先,应用程序确定要包含在 JWT 中的信息,即构建头部和载荷部分。这可能包括用户身份信息、权限信息、过期时间等。
例如,一个简单的用户认证场景,头部可能指定算法为 HS256,载荷包含用户 ID 和用户名等信息。
步骤二:编码头部和载荷
将构建好的头部和载荷的 JSON 对象分别进行 Base64Url 编码。Base64Url 编码是一种对 Base64 编码的变体,它使编码后的字符串更适合在 URL 和文件名等场景中使用,因为它去掉了 Base64 编码中的一些特殊字符(如 “+”、“/” 和 “=”)。
步骤三:生成签名
使用选定的签名算法(如 HS256)和密钥,对编码后的头部和载荷进行签名计算。如果是 HS256 算法,会对头部和载荷的组合(用 “.” 连接)进行 HMAC – SHA256 计算。
例如,假设头部编码后为headerEncoded,载荷编码后为payloadEncoded,密钥为secretKey,那么签名signature的计算方式大致为:signature = HMAC – SHA256(secretKey, headerEncoded + ‘.’ + payloadEncoded)。
步骤四:组合成 JWT
最后,将编码后的头部、载荷和签名用 “.” 连接起来,形成最终的 JWT,格式为header.payload.signature。这个 JWT 可以被发送给客户端,例如在用户登录成功后作为身份认证令牌发送。
1.4 验证 JWT 的流程
步骤一:拆分 JWT
当客户端发送 JWT 到服务器进行验证时,服务器首先将 JWT 按照 “.” 拆分为头部、载荷和签名三个部分。
步骤二:解码头部和载荷
对拆分出的头部和载荷部分进行 Base64Url 解码,得到原始的 JSON 对象。这样可以获取其中包含的信息,如令牌类型、签名算法、用户信息等。
步骤三:重新计算签名
根据解码后的头部信息获取签名算法,使用与生成 JWT 时相同的密钥,按照相同的签名算法对解码后的头部和载荷进行重新签名计算。
例如,如果头部中的算法是 HS256,密钥是secretKey,头部解码后为headerDecoded,载荷解码后为payloadDecoded,那么重新计算签名newSignature的方式大致为:newSignature = HMAC – SHA256(secretKey, headerDecoded + ‘.’ + payloadDecoded)。
步骤四:验证签名
将重新计算得到的签名与接收到的签名进行比较。如果两者相同,说明 JWT 在传输过程中没有被篡改,并且是由拥有正确密钥的一方生成的。此时可以信任 JWT 中的信息,并根据其中的载荷信息(如用户权限等)进行后续的操作,如授权访问资源。如果签名不匹配,则说明 JWT 可能被篡改或者密钥不正确,应该拒绝该 JWT。
1.5 JWT使用场景
授权:用户登录后,每次请求中包含JWT,以允许用户访问被授权的资源。
信息交换:安全地在各方之间传递信息,因其可以被签名以验证发件人身份和内容完整性。
2 JJWT——JWT的实现之一
JJWT 是一个专门为 Java 开发者设计的库,用于方便地创建、解析和验证 JWT,旨在提供简单易用的API。它支持在JVM和Android环境中使用,并遵循JWT、JWS、JWE等RFC规范。JJWT是一个开源项目,可以通过maven引入依赖:
<dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>${jwt.version}</version> </dependency>
2.1 JJWT的基本使用
2.1.1 生成JWT
以下是一个简单的使用JJWT生成JWT的示例代码:
public static String createJWT(Map<String, Object> header, Map<String, Object> claims, String subject, long ttlMillis) { return Jwts.builder() .setHeader(header) .setClaims(claims) .setSubject(subject) .setIssuedAt(new Date()) .setExpiration(new Date(System.currentTimeMillis() + ttlMillis)) .signWith(SignatureAlgorithm.HS256, SECRET) .compact(); }
上面的方法创建了一个带有声明、主题、生成时间及有效期的JWT,并使用HMAC SHA512算法进行签名。
2.1.2 解析和验证JWT
以下示例代码演示了如何解析和验证JWT:
public static void parseJWT(String jwt) { try { Claims body = Jwts.parser().setSigningKey(SECRET).parseClaimsJws(jwt).getBody(); System.out.println(body); } catch (Exception e) { e.printStackTrace(); } }
在解析时,使用 Jwts.parser() 创建一个解析器,通过 setSigningKey() 设置正确的密钥,然后使用 parseClaimsJws() 方法解析 JWT。如果签名验证成功,将返回 Claims 对象,其中包含了载荷中的信息;如果签名验证失败或者 JWT 格式不正确等,将抛出异常。
下面是完整的示例:
import io.jsonwebtoken.*; import java.util.Date; import java.util.HashMap; import java.util.Map; public class JwtUtil { private static final String SECRET = "a3f5e2c8b6d1e9f0c4a7b8d9e5c3f2a1b0e6d4c7f8a9b0c1d2e3f4a5b6c7d8e9"; private static final String SECRET1 = "your_secret_key1"; public static void main(String[] args) { //定义头部 HashMap<String, Object> headers = new HashMap<>(); headers.put("alg", "HS512"); headers.put("type", "JWT"); //定义载荷 HashMap<String, Object> claims = new HashMap<>(); claims.put("user_id", 123); claims.put("username", "peter"); //定义主题 String subject = "subject"; //定义存活时间为一个小时 long ttlMillis = 1 * 60 * 60 * 1000; String jwt = createJWT(headers, claims, subject, ttlMillis); System.out.println("JWT: " + jwt); parseJWT(jwt); } public static String createJWT(Map<String, Object> header, Map<String, Object> claims, String subject, long ttlMillis) { return Jwts.builder() .setHeader(header) .setClaims(claims) .setSubject(subject) .setIssuedAt(new Date()) .setExpiration(new Date(System.currentTimeMillis() + ttlMillis)) .signWith(SignatureAlgorithm.HS256, SECRET) .compact(); } public static void parseJWT(String jwt) { try { Claims body = Jwts.parser().setSigningKey(SECRET).parseClaimsJws(jwt).getBody(); System.out.println(body); } catch (Exception e) { e.printStackTrace(); } } }
3 总结
JWT 是开放标准,由 Header、Payload、Signature 组成,用于安全传递信息,适用于身份验证与信息交换等场景。JJWT 是其 Java 实现库,可便捷创建、解析和验证 JWT,如通过特定方法生成并验证,遵循相关规范且开源,在 Java 开发中有重要应用。
我是欧阳方超,把事情做好了自然就有兴趣了,如果你喜欢我的文章,欢迎点赞、转发、评论加关注。我们下次见。
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/166670.html