iis服务器助手广告广告
返回顶部
首页 > 资讯 > 前端开发 > JavaScript >一文了解什么是JWT
  • 764
分享到

一文了解什么是JWT

JWT 2023-05-19 14:05:23 764人浏览 八月长安
摘要

目录起源session认证token认证什么是JwtJWT的数据结构HeaderPayloadSignatureJWT的优点怎么使用JWT总结起源 需要了解一门技术,首先从为什么产生

起源

需要了解一门技术,首先从为什么产生开始说起是最好的。JWT 主要用于用户登录鉴权,所以我们从最传统的 session 认证开始说起。

session认证

众所周知,Http 协议本身是无状态的协议,那就意味着当有用户向系统使用账户名称和密码进行用户认证之后,下一次请求还要再一次用户认证才行。因为我们不能通过 http 协议知道是哪个用户发出的请求,所以如果要知道是哪个用户发出的请求,那就需要在服务器保存一份用户信息(保存至 session ),然后在认证成功后返回 cookie 值传递给浏览器,那么用户在下一次请求时就可以带上 cookie 值,服务器就可以识别是哪个用户发送的请求,是否已认证,是否登录过期等等。这就是传统的 session 认证方式。

session 认证的缺点其实很明显,由于 session 是保存在服务器里,所以如果分布式部署应用的话,会出现session不能共享的问题,很难扩展。于是乎为了解决 session 共享的问题,又引入了 Redis,接着往下看。

token认证

这种方式跟 session 的方式流程差不多,不同的地方在于保存的是一个 token 值到 redis,token 一般是一串随机的字符(比如UUID),value 一般是用户ID,并且设置一个过期时间。每次请求服务的时候带上 token 在请求头,后端接收到token 则根据 token 查一下 redis 是否存在,如果存在则表示用户已认证,如果 token 不存在则跳到登录界面让用户重新登录,登录成功后返回一个 token 值给客户端。

优点是多台服务器都是使用 redis 来存取 token,不存在不共享的问题,所以容易扩展。缺点是每次请求都需要查一下redis,会造成 redis 的压力,还有增加了请求的耗时,每个已登录的用户都要保存一个 token 在 redis,也会消耗 redis 的存储空间。

有没有更好的方式呢?接着往下看。

什么是JWT

JWT (全称:JSON WEB Token)是一个开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式,用于作为 jsON 对象在各方之间安全地传输信息。该信息可以被验证和信任,因为它是数字签名的。

上面说法比较文绉绉,简单点说就是一种认证机制,让后台知道该请求是来自于受信的客户端。

首先我们先看一个流程图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7UDQ9SEm-1653810812356)(什么是JWT.assets/v2-bd0aeaf5ba1bad5ab1edff601e9b7a78_720w.jpg)]

流程描述一下:

  • 用户使用账号、密码登录应用,登录的请求发送到 Authentication Server。
  • Authentication Server 进行用户验证,然后创建 JWT 字符串返回给客户端。
  • 客户端请求接口时,在请求头带上 JWT。
  • Application Server 验证 JWT 合法性,如果合法则继续调用应用接口返回结果。

可以看出与token方式有一些不同的地方,就是不需要依赖 redis,用户信息存储在客户端。所以关键在于生成 JWT 和解析 JWT 这两个地方。

JWT的数据结构

JWT 一般是这样一个字符串,分为三个部分,以 “.” 隔开:

xxxxx.yyyyy.zzzzz

Header

JWT 第一部分是头部分,它是一个描述 JWT 元数据的 Json 对象,通常如下所示。

{
    "alg": "HS256",
    "typ": "JWT"
}

alg 属性表示签名使用的算法,默认为 HMac SHA256(写为HS256),typ 属性表示令牌的类型,JWT 令牌统一写为JWT。

最后,使用 Base64 URL 算法将上述 JSON 对象转换为字符串保存。

Payload

JWT 第二部分是 Payload,也是一个 Json 对象,除了包含需要传递的数据,还有七个默认的字段供选择。

  • iss (issuer):签发人/发行人
  • sub (subject):主题
  • aud (audience):用户
  • exp (expiration time):过期时间
  • nbf (Not Before):生效时间,在此之前是无效的
  • iat (Issued At):签发时间
  • jti (JWT ID):用于标识该 JWT

如果自定义字段,可以这样定义:

{
    //默认字段
    "sub":"主题123",
    //自定义字段
    "name":"java技术爱好者",
    "isAdmin":"true",
    "loginTime":"2021-12-05 12:00:03"
}

需要注意的是,默认情况下 JWT 是未加密的,任何人都可以解读其内容,因此一些敏感信息不要存放于此,以防信息泄露。

JSON 对象也使用 Base64 URL 算法转换为字符串后保存,是可以反向反编码回原样的,这也是为什么不要在 JWT 中放敏感数据的原因。

Signature

header (base64URL 加密后的)
payload (base64URL 加密后的)
secret

JWT 第三部分是签名。是这样生成的,首先需要指定一个 secret,该 secret 仅仅保存在服务器中,保证不能让其他用户知道。这个部分需要 base64URL 加密后的 header 和 base64URL 加密后的 payload 使用 . 连接组成的字符串,然后通过header 中声明的加密算法 进行加盐secret组合加密,然后就得出一个签名哈希,也就是Signature,且无法反向解密。

那么 Application Server 如何进行验证呢?可以利用 JWT 前两段,用同一套哈希算法和同一个 secret 计算一个签名值,然后把计算出来的签名值和收到的 JWT 第三段比较,如果相同则认证通过。

JWT的优点

  • json格式的通用性,所以JWT可以跨语言支持,比如Java、javascriptPHPnode等等。
  • 可以利用Payload存储一些非敏感的信息。
  • 便于传输,JWT结构简单,字节占用小。
  • 不需要在服务端保存会话信息,易于应用的扩展。

怎么使用JWT

首先引入Maven依赖。

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

创建工具类,用于创建(生成) jwt 字符串和解析 jwt。

@Component
public class JwtUtil {
    @Value("${jwt.secreTKEy}")
    private String secretKey;
    public String createJWT(String id, String subject, long ttlMillis, Map<String, Object> map) throws Exception {
        JwtBuilder builder = Jwts.builder()
                .setId(id)
                .setSubject(subject) // 发行者
                .setIssuedAt(new Date()) // 发行时间
                .signWith(SignatureAlGorithm.HS256, secretKey) // 签名类型 与 密钥
                .compressWith(CompressionCodecs.DEFLATE);// 对载荷进行压缩
        if (!CollectionUtils.isEmpty(map)) {
            builder.setClaims(map);
        }
        if (ttlMillis > 0) {
            builder.setExpiration(new Date(System.currentTimeMillis() + ttlMillis));
        }
        return builder.compact();
    }
    public Claims parseJWT(String jwtString) {
        return Jwts.parser().setSigningKey(secretKey)
                .parseClaimsJws(jwtString)
                .getBody();
    }
}

接着在application.yml配置文件配置jwt.secretKey

## 用户生成jwt字符串的secretKey
jwt:
  secretKey: ak47

接着创建一个响应体。

public class BaseResponse {
    private String code;
    private String msg;
    public static BaseResponse success() {
        return new BaseResponse("0", "成功");
    }
    public static BaseResponse fail() {
        return new BaseResponse("1", "失败");
    }
    //构造器、getter、setter方法
}
public class JwtResponse extends BaseResponse {
    private String jwtData;
    public static JwtResponse success(String jwtData) {
        BaseResponse success = BaseResponse.success();
        return new JwtResponse(success.getCode(), success.getMsg(), jwtData);
    }
    public static JwtResponse fail(String jwtData) {
        BaseResponse fail = BaseResponse.fail();
        return new JwtResponse(fail.getCode(), fail.getMsg(), jwtData);
    }
    //构造器、getter、setter方法
}

接着创建一个UserController:

@RestController
@RequestMapping("/user")
public class UserController {

    @Resource
    private UserService userService;

    @RequestMapping(value = "/login", method = RequestMethod.POST)
    public JwtResponse login(@RequestParam(name = "userName") String userName,
                             @RequestParam(name = "passWord") String passWord){
        String jwt = "";
        try {
            jwt = userService.login(userName, passWord);
            return JwtResponse.success(jwt);
        } catch (Exception e) {
            e.printStackTrace();
            return JwtResponse.fail(jwt);
        }
    }
}

还有UserService:

@Service
public class UserServiceImpl implements UserService {

    @Resource
    private JwtUtil jwtUtil;

    @Resource
    private UserMapper userMapper;

    @Override
    public String login(String userName, String passWord) throws Exception {
        //登录验证
        User user = userMapper.findByUserNameAndPassword(userName, passWord);
        if (user == null) {
            return null;
        }
        //如果能查出,则表示账号密码正确,生成jwt返回
        String uuid = UUID.randomUUID().toString().replace("-", "");
        HashMap<String, Object> map = new HashMap<>();
        map.put("name", user.getName());
        map.put("age", user.getAge());
        return jwtUtil.createJWT(uuid, "login subject", 0L, map);
    }
}

还有UserMapper.xml:

@Mapper
public interface UserMapper {
    User findByUserNameAndPassword(@Param("userName") String userName, @Param("passWord") String passWord);

}

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="io.GitHub.yehongzhi.jwtdemo.mapper.UserMapper">
    <select id="findByUserNameAndPassword" resultType="io.github.yehongzhi.jwtdemo.model.User">
        select * from user where user_name = #{userName} and pass_word = #{passWord}
    </select>
</mapper>

user 表结构如下:

启动项目,然后用 postman 请求 login 接口。

返回的 jwt 字符串如下:

eyJhbGCiOiJIUzI1NiIsInppcCI6IkRFRiJ9.eNqqVspLzE1VslJ6OnHFsxnzX67coKSjlJgOFDEzqAUAAAD__w.qib2DrjRKcFnY77Cuh_b1zSzXfISOpCA-g8PlAZCWoU

接着我们写一个接口接收这个 jwt,并做验证。

@RestController
@RequestMapping("/jwt")
public class TestController {
    @Resource
    private JwtUtil jwtUtil;
    @RequestMapping("/test")
    public Map<String, Object> test(@RequestParam("jwt") String jwt) {
        //这个步骤可以使用自定义注解+aop编程做解析jwt的逻辑,这里为了简便就直接写在controller里
        Claims claims = jwtUtil.parseJWT(jwt);
        String name = claims.get("name", String.class);
        String age = claims.get("age", String.class);
        HashMap<String, Object> map = new HashMap<>();
        map.put("name", name);
        map.put("age", age);
        map.put("code", "0");
        map.put("msg", "请求成功");
        return map;
    }
}

像这样能正常解析成功的话,就表示该用户登录未过期,并且已认证成功,所以可以正常调用服务。那么有人会问了,这个 jwt 字符串能不能被伪造呢?

除非你知道 secretKey,否则是不能伪造的。比如客户端随便猜一个 secretKey 的值,然后伪造一个jwt:

eyJhbGciOiJIUzI1NiIsInppcCI6IkRFRiJ9.eNqqVspLzE1VslJ6OnHFsxnzX67coKSjlJgOFDEzqAUAAAD__w.bHr9p3-t2qR4R50vifRVyaYYImm2viZqiTlDdZHmF5Y

然后传进去解析,会报以下错误:

还记得原理吧,是根据前面两部分(Header、Payload)加上 secretKey 使用 Header 指定的哈希算法计算出第三部分(Signature),所以可以看出最关键就是 secretKey。secretKey只有服务端自己知道,所以客户端不知道 secretKey 的值是伪造不了jwt字符串的。

总结

最后讲讲 JWT 的缺点,因为任何技术都不是完美的,所以我们得用辩证思维去看待任何一项技术。

安全性没法保证,所以 jwt 里不能存储敏感数据。因为 jwt 的 payload 并没有加密,只是用 Base64 编码而已。无法中途废弃。因为一旦签发了一个 jwt,在到期之前始终都是有效的,如果用户信息发生更新了,只能等旧的 jwt 过期后重新签发新的 jwt。续签问题。当签发的 jwt 保存在客户端,客户端一直在操作页面,按道理应该一直为客户端续长有效时间,否则当 jwt有效期到了就会导致用户需要重新登录。那么怎么为 jwt 续签呢?最简单粗暴就是每次签发新的 jwt,但是由于过于暴力,会影响性能。如果要优雅一点,又要引入 Redis 解决,但是这又把无状态的 jw t硬生生变成了有状态的,违背了初衷。

所以印证了那句话,没有最好的技术,只有适合的技术。

到此这篇关于一文了解什么是JWT的文章就介绍到这了,更多相关JWT内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: 一文了解什么是JWT

本文链接: https://www.lsjlt.com/news/213341.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 一文了解什么是JWT
    目录起源session认证token认证什么是JWTJWT的数据结构HeaderPayloadSignatureJWT的优点怎么使用JWT总结起源 需要了解一门技术,首先从为什么产生...
    99+
    2023-05-19
    JWT
  • 一文了解Hive是什么
    目录一、Hive介绍Hive的优缺点Hive架构Hive用户接口Hive元数据的三种存储模式Hive数据存储架构原理Hive文件格式Hive本质Hive工作原理Hive数据类型一、H...
    99+
    2024-04-02
  • 一文了解什么是TypeScript?
    目录1.JavaScript的问题2.TypeScript的优势3.TypeScript的缺点4.TypeScript的运行环境5.作用域问题前言: TypeScript是Java...
    99+
    2024-04-02
  • 什么是JWT超详细讲解
    什么是JWT? JWT(json web token),它并不是一个具体的技术实现,而更像是一种标准。 Json web token (JWT), 是为了在网络应用环境间传递声明而执...
    99+
    2022-12-08
    JWT是什么 什么是JWT .net JWT
  • 一文了解什么是CDN及实现原理
    目录正文dns解析流程让我们来一步步分析解析流程:腾讯云cdn实例正文 由于用户访问源站业务有性能瓶颈,通过cdn技术把源站的内容缓存到多个节点。用户向源站域名发起请求时,请求会被调...
    99+
    2023-05-19
    CDN实现原理 什么是CDN
  • 什么是JWT?深入理解JWT从原理到应用
    🎉🎉欢迎来到我的CSDN主页!🎉🎉 🏅我是Java方文山,一个在CSDN分享笔记的博主。📚📚 🌟推荐给...
    99+
    2023-10-08
    jwt jjwt-root session
  • WAF是什么?一篇文章带你全面了解WAF
    WAF是什么?一篇文章带你全面了解WAF 文章目录 WAF是什么?一篇文章带你全面了解WAFWAF是什么?一、WAF的工作原理二、WAF的分类三、WAF的特点四、如何选择和部署WAF WAF是什么? Web应用程序防火墙(W...
    99+
    2023-08-21
    服务器 前端 网络 安全 web安全
  • 什么是Cookie、Session、Token、JWT
    这篇文章主要介绍“什么是Cookie、Session、Token、JWT”,在日常操作中,相信很多人在什么是Cookie、Session、Token、JWT问题上存在疑惑,小编查阅了各式资料,整理出简单好用...
    99+
    2024-04-02
  • nodejs中的jwt是什么
    这篇文章主要讲解了“nodejs中的jwt是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“nodejs中的jwt是什么”吧! ...
    99+
    2024-04-02
  • 为什么jwt避免了csrf攻击
    jwt全称Json Web Token,是一个长字符串,由Header(头部)、 Payload(负载)、Signature(签名)三部分组成。使用jwt验证,由于服务端不保存用户信息,不需要做sessonid复制,同时用户发请求给服务端时...
    99+
    2024-04-02
  • 一文带你全面了解什么是自动化测试?
    目录 简介 自动化测试概述 自动化测试目标 自动化测试流程 1. 测试计划和设计 2. 测试脚本开发 3. 测试执行和管理 4. 测试维护和优化 自动化测试最佳实践 自动化测试工具和框架 结论 简介 软件测试是软件开发过程中一个必不可...
    99+
    2023-10-02
    单元测试 测试用例 压力测试 自动化测试 python
  • JWT的数据结构是什么
    这篇文章主要介绍“JWT的数据结构是什么”,在日常操作中,相信很多人在JWT的数据结构是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”JWT的数据结构是什么”的疑惑有所帮助!接下来,请跟着小编一起来学习吧...
    99+
    2023-07-04
  • JWT是什么?Node中怎么实现JWT鉴权机制(浅析)
    【相关教程推荐:nodejs视频教程】一、为什么使用JWT一种技术的出现,就是弥补另一种技术的的缺陷。在JWT出现之前,Session 认证机制需要配合 Cookie 才能实现。由于 Cookie 默认不支持跨域访问,所以,当涉及到前端跨域...
    99+
    2022-11-22
    nodejs​ node
  • JWT的原理及用法是什么
    本篇内容介绍了“JWT的原理及用法是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!一、跨域认证的问题互联网服务离不开用户认证。一般流程是...
    99+
    2023-07-04
  • Session、JWT与OAuth2的特点是什么
    这篇文章主要讲解了“Session、JWT与OAuth2的特点是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Session、JWT与OAuth2的特点是什么”吧!Session模式浏览...
    99+
    2023-06-26
  • 一文解答什么是MySQL的回表
    目录引言聚簇索引和非聚簇索引是什么?主键索引和非主键索引有什么区别?B-Tree 和 B+Tree 的简单理解如何避免回表?引言 简单来说,回表就是 MySQL 要先查询到主键索引,...
    99+
    2022-11-13
    MySQL回表 回表
  • PHP bom到底是什么?一文解析
    PHP bom 到底是什么?一文解析 在编程领域中,很多程序员们在处理 PHP 文件时都会遇到 bom 的问题。那么,PHP bom到底是什么呢?让我们来一探究竟。 一、BOM是什么 ...
    99+
    2024-03-10
    php 解析 bom
  • Golang Bee 究竟是什么?深入了解一下
    Golang Bee 究竟是什么?深入了解一下,需要具体代码示例 随着 Go 语言在开发领域的日益流行,Golang Bee 作为一个快速且强大的 Web 开发框架也逐渐走进了开发者的...
    99+
    2024-03-06
    深入 bee
  • 一文了解为什么Java中只有值传递
    目录经典的问题形参&实参Java是值传递还是引用传递传参的类型:基本数据类型传参的类型:引用数据类型尾语经典的问题 Java 传参是值传递还是引用传递?这个问题很基础,但是许...
    99+
    2024-04-02
  • jwt的token机制原理是什么
    JWT(JSON Web Token)是一种用于身份验证和授权的开放标准(RFC 7519),它是一种轻量级的无状态身份验证机制,用...
    99+
    2023-10-07
    jwt
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作