JWT(Json web token)认证详解
JWT的定义:
JWT是一种用于双方之间传递安全信息的简洁的、URL安全的表述性声明规范。JWT作为一个开放的标准(RFC 7519),定义了一种简洁的,自包含的方法用于通信双方之间以Json对象的形式安全的传递信息。因为数字签名的存在,这些信息是可信的,JWT可以使用HMAC算法或者是RSA的公私秘钥对进行签名。
JWT特点:
简洁(Compact): 可以通过URL,POST参数或者在HTTP header发送,因为数据量小,传输速度也很快
自包含(Self-contained):负载中包含了所有用户所需要的信息,避免了多次查询数据库
JWT结构:
JWT主要包含Header 头部 Payload 负载 Signature 签名,顺序是 header.payload.signature 三部分之间用英语句号’.'隔开
Header头部
头部包含了两部分,token 类型(“JWT”)和采用的加密算法(HMAC SHA256或者RSA等等)
例如:
然后,用Base64对这个JSON编码就得到JWT的第一部分
Payload负载
这部分就是我们存放信息的地方了,你可以把用户 ID 等信息放在这里,JWT 规范里面对这部分有进行了比较详细的介绍,常用的由 iss(签发者),exp(过期时间),sub(面向的用户),aud(接收方),iat(签发时间)。
同样的,它会使用 Base64 编码组成 JWT 结构的第二部分。
Signature签名
前面两部分都是使用 Base64 进行编码的,即前端可以解开知道里面的信息。Signature 需要使用Base64编码后的 header 和 payload 以及我们提供的一个密钥,然后使用 header 中指定的签名算法(HS256)进行签名。签名的作用是保证 JWT 没有被篡改过。三个部分通过.
连接在一起就是我们的 JWT 了,它可能长这个样子,长度貌似和你的加密算法和私钥有关系。
1 | eyJhbGciOiJIUzI1NiIsIlR5cGUiOiJKd3QiLCJ0eXAiOiJKV1QifQ.eyJsb2dpblRpbWUiOiIyMDIxLTEwLTI3VDE1OjIxOjU4LjU3OCIsInVzZXJOYW1lIjoi5rGf5Y2XIiwiZXhwIjoxNjM1MzIxMTE4fQ.lUojZpIGx0a65s5FrgYlQio0vf3jOuqWOTP-DUjzGh0 |
JSON Web Tokens是如何工作的?
一般是在请求头里加入Authorization
,并加上Bearer
标注:
1 2 3 4 5 | fetch( 'api/user/1' , { headers: { 'Authorization' : 'Bearer ' + token } }) |
服务端会验证token,如果验证通过就会返回相应的资源。整个流程就是这样的:
优点
- 因为json的通用性,所以JWT是可以进行跨语言支持的,像JAVA,JavaScript,NodeJS,PHP等很多语言都可以使用。
- 因为有了payload部分,所以JWT可以在自身存储一些其他业务逻辑所必要的非敏感信息。
- 便于传输,jwt的构成非常简单,字节占用很小,所以它是非常便于传输的。
- 它不需要在服务端保存会话信息, 所以它易于应用的扩展
安全相关
- 不应该在jwt的payload部分存放敏感信息,因为该部分是客户端可解密的部分。
- 保护好secret私钥,该私钥非常重要。
- 如果可以,请使用https协议
最后附上Token工具类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | import com.auth0.jwt.JWT; import com.auth0.jwt.JWTVerifier; import com.auth0.jwt.algorithms.Algorithm; import com.auth0.jwt.exceptions.JWTDecodeException; import com.auth0.jwt.interfaces.DecodedJWT; import java.time.LocalDateTime; import java.util.Date; import java.util.HashMap; import java.util.Map; public class TokenUtil { /** * token过期时间 */ private static final long EXPIRE_TIME = 30 * 60 * 1000 ; /** * token秘钥 */ private static final String TOKEN_SECRET = "secret" ; /** * 生成token,30分钟过期 * * @param userName 用户名 * @param loginTime 登录时间 * @return 生成的token */ public static String sign(String userName, LocalDateTime loginTime) { try { // 设置过期时间 Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME); System.out.println(date); // 私钥和加密算法 Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET); // 设置头部信息 Map<String, Object> header = new HashMap<>( 3 ); header.put( "Type" , "Jwt" ); header.put( "alg" , "HS256" ); // 返回token字符串 return JWT.create() .withHeader(header) // 设置token中需要加载的用户信息 存储自己想要留给前端的内容 .withClaim( "userName" , userName) .withClaim( "loginTime" , loginTime.toString()) .withExpiresAt(date) .sign(algorithm); } catch (Exception e) { e.printStackTrace(); return null ; } } /** * 检验token是否正确 */ public static boolean verify(String token) { try { //设置签名的加密算法:HMAC256 Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET); JWTVerifier verifier = JWT.require(algorithm).build(); verifier.verify(token); return true ; } catch (Exception e) { return false ; } } /** * 获取token中信息 userName */ public static String getUsername(String token) { try { DecodedJWT jwt = JWT.decode(token); return jwt.getClaim( "userName" ).asString(); } catch (JWTDecodeException e) { e.printStackTrace(); } return null ; } } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· Vue3状态管理终极指南:Pinia保姆级教程