面试官:什么是JWT?为什么要用JWT?

本文介绍了JWT(JSONWebToken)的概念、优点,如无状态、跨域支持和适应微服务架构,并展示了在Java开发中的使用方法和原理。JWT是一种安全的认证机制,尤其适合现代分布式系统。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目前传统的后台管理系统,以及不使用第三方登录的系统,使用 JWT 技术的还是挺多的,因此在面试中被问到的频率也比较高,所以今天我们就来看一下:什么是 JWT?为什么要用 JWT?

1.什么是 JWT?

JWT(JSON Web Token)是一种开放标准(RFC 7519),用于在网络上安全传输信息的简洁、自包含的方式。它通常被用于身份验证和授权机制。 JWT 由三部分组成:头部(Header)、载荷(Payload)和签名(Signature)。

  1. 头部(Header):包含了关于生成该 JWT 的信息以及所使用的算法类型。
  2. 载荷(Payload):包含了要传递的数据,例如身份信息和其他附属数据。JWT 官方规定了 7 个字段,可供使用:
    1. iss (Issuer):签发者。
    2. sub (Subject):主题。
    3. aud (Audience):接收者。
    4. exp (Expiration time):过期时间。
    5. nbf (Not Before):生效时间。
    6. iat (Issued At):签发时间。
    7. jti (JWT ID):编号。
  3. 签名(Signature):使用密钥对头部和载荷进行签名,以验证其完整性。

JWT 官网:jwt.io/

2.为什么要用 JWT?

JWT 相较于传统的基于会话(Session)的认证机制,具有以下优势:

  1. 无需服务器存储状态:传统的基于会话的认证机制需要服务器在会话中存储用户的状态信息,包括用户的登录状态、权限等。而使用 JWT,服务器无需存储任何会话状态信息,所有的认证和授权信息都包含在 JWT 中,使得系统可以更容易地进行水平扩展。
  2. 跨域支持:由于 JWT 包含了完整的认证和授权信息,因此可以轻松地在多个域之间进行传递和使用,实现跨域授权。
  3. 适应微服务架构:在微服务架构中,很多服务是独立部署并且可以横向扩展的,这就需要保证认证和授权的无状态性。使用 JWT 可以满足这种需求,每次请求携带 JWT 即可实现认证和授权。
  4. 自包含:JWT 包含了认证和授权信息,以及其他自定义的声明,这些信息都被编码在 JWT 中,在服务端解码后使用。JWT 的自包含性减少了对服务端资源的依赖,并提供了统一的安全机制。
  5. 扩展性:JWT 可以被扩展和定制,可以按照需求添加自定义的声明和数据,灵活性更高。

总结来说,使用 JWT 相较于传统的基于会话的认证机制,可以减少服务器存储开销和管理复杂性,实现跨域支持和水平扩展,并且更适应无状态和微服务架构。

3.JWT 基本使用

在 Java 开发中,可以借助 JWT 工具类来方便的操作 JWT,例如 HuTool 框架中的 JWTUtil。

HuTool 介绍:doc.hutool.cn/pages/JWTUt…

使用 HuTool 操作 JWT 的步骤如下:

  1. 添加 HuTool 框架依赖
  2. 生成 Token
  3. 验证和解析 Token

3.1 添加 HuTool 框架依赖

在 pom.xml 中添加以下信息:

 

xml

复制代码

<dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.8.16</version> </dependency>

3.2 生成 Token

 

java

复制代码

Map<String, Object> map = new HashMap<String, Object>() { private static final long serialVersionUID = 1L; { put("uid", Integer.parseInt("123")); // 用户ID put("expire_time", System.currentTimeMillis() + 1000 * 60 * 60 * 24 * 15); // 过期时间15天 } }; JWTUtil.createToken(map, "服务器端秘钥".getBytes());

3.3 验证和解析 Token

验证 Token 的示例代码如下:

 

java

复制代码

String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbImFsbCJdLCJleHAiOjE2MjQwMDQ4MjIsInVzZXJJZCI6MSwiYXV0aG9yaXRpZXMiOlsiUk9MRV_op5LoibLkuozlj7ciLCJzeXNfbWVudV8xIiwiUk9MRV_op5LoibLkuIDlj7ciLCJzeXNfbWVudV8yIl0sImp0aSI6ImQ0YzVlYjgwLTA5ZTctNGU0ZC1hZTg3LTVkNGI5M2FhNmFiNiIsImNsaWVudF9pZCI6ImhhbmR5LXNob3AifQ.aixF1eKlAKS_k3ynFnStE7-IRGiD5YaqznvK2xEjBew"; JWTUtil.verify(token, "123456".getBytes());

解析 Token 的示例代码如下:

 

java

复制代码

String rightToken = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiYWRtaW4iOnRydWUsIm5hbWUiOiJsb29seSJ9.U2aQkC2THYV9L0fTN-yBBI7gmo5xhmvMhATtu8v0zEA"; final JWT jwt = JWTUtil.parseToken(rightToken); jwt.getHeader(JWTHeader.TYPE); jwt.getPayload("sub");

3.4 代码实战

在登录成功之后,生成 Token 的示例代码如下:

 

java

复制代码

// 登录成功,使用 JWT 生成 Token Map<String, Object> payload = new HashMap<String, Object>() { private static final long serialVersionUID = 1L; { put("uid", userinfo.getUid()); put("manager", userinfo.getManager()); // JWT 过期时间为 15 天 put("exp", System.currentTimeMillis() + 1000 * 60 * 60 * 24 * 15); } }; String token = JWTUtil.createToken(payload, AppVariable.JWT_KEY.getBytes());

例如在 Spring Cloud Gateway 网关中验证 Token 的实现代码如下:

 

java

复制代码

import cn.hutool.jwt.JWT; import cn.hutool.jwt.JWTUtil; import com.example.common.AppVariable; import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.core.Ordered; import org.springframework.http.HttpStatus; import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.stereotype.Component; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; import java.util.List; /** * 登录过滤器(登录判断) */ @Component public class AuthFilter implements GlobalFilter, Ordered { // 排除登录验证的 URL 地址 private String[] skipAuthUrls = {"/user/add", "/user/login"}; @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { // 当前请求的 URL String url = exchange.getRequest().getURI().getPath(); for (String item : skipAuthUrls) { if (item.equals(url)) { // 继续往下走 return chain.filter(exchange); } } ServerHttpResponse response = exchange.getResponse(); // 登录判断 List<String> tokens = exchange.getRequest().getHeaders().get(AppVariable.TOKEN_KEY); if (tokens == null || tokens.size() == 0) { // 当前未登录 response.setStatusCode(HttpStatus.UNAUTHORIZED); return response.setComplete(); } // token 有值 String token = tokens.get(0); // JWT 效验 token 是否有效 boolean result = false; try { result = JWTUtil.verify(token, AppVariable.JWT_KEY.getBytes()); } catch (Exception e) { result = false; } if (!result) { // 无效 token response.setStatusCode(HttpStatus.UNAUTHORIZED); return response.setComplete(); } else { // 判断 token 是否过期 final JWT jwt = JWTUtil.parseToken(token); // 得到过期时间 Object expObj = jwt.getPayload("exp"); if (expObj == null) { response.setStatusCode(HttpStatus.UNAUTHORIZED); return response.setComplete(); } long exp = Long.parseLong(expObj.toString()); if (System.currentTimeMillis() > exp) { // token 过期 response.setStatusCode(HttpStatus.UNAUTHORIZED); return response.setComplete(); } } return chain.filter(exchange); } @Override public int getOrder() { // 值越小越早执行 return 1; } }

4.实现原理分析

JWT 本质是将秘钥存放在服务器端,并通过某种加密手段进行加密和验证的机制。加密签名=某加密算法(header+payload+服务器端私钥),因为服务端私钥别人不能获取,所以 JWT 能保证自身其安全性。

小结

JWT 相比与传统的 Session 会话机制,具备无状态性(无需服务器端存储会话信息),并且它更加灵活、更适合微服务环境下的登录和授权判断。JWT 是由三部分组成的:Header(头部)、Payload(数据载荷)和 Signature(签名)。

本文已收录到我的面试小站 资料免费获取链接 (qq.com)icon-default.png?t=N7T8https://docs.qq.com/doc/DQXdYWE9LZ2ZHZ1ho,其中包含的内容有:Redis、JVM、并发、并发、MySQL、Spring、Spring MVC、Spring Boot、Spring Cloud、MyBatis、设计模式、消息队列等模块。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值