基于SpringBoot的JWT令牌验证简易过程(上)

fe691f7db27a4d07a80870435e194460.png

关键词知悉

会话:当打开浏览器并访问Web服务器上的资源时,就会建立一个会话。一个会话包括多次请求和响应。例如,登录教学系统会发起一次请求并得到响应,查询课程也会发起一次请求并得到响应。

会话跟踪:服务器识别多个请求是否来自同一浏览器的过程,目的是在同一会话中的多次请求之间共享数据,例如获取验证码并校对获取过的验证码(两个请求)。

HTTP无状态:每个请求都是独立的,没有相互关联,无法共享数据。解决方法是使用会话跟踪。

跟踪方案

           Cookie, 不能进行跨域请求,可以被用户禁用,不够安全。

           Session,在服务器集群中无法直接共享。

           JWT 令牌,需要自行实现,无法伪造

JWT令牌

本质上是一个字符串,它定义了一种简洁且自包含的格式,用于在通信双方之间以JSON数据格式安全传输信息。令牌由以下三个部分组成:

eyJhbGciOiJIUzI1NiJ9.
eyJuYW1lIjoiam9pbiIsImlkIjoxLCJleHAiOjE3MjUwNjc5NjJ9.
3GoCTzD_Hd0hp5E1snA8Dta2UTytTNyH7GrP78Z_5kU

Header(头部):记录签名类型及所用的签名算法,例如:{"alg":"HS256","typ":"JWT"}。

Payload(有效载荷):包含自定义信息以及默认信息,如:{"id":1,"name":"张三"}。

Signature(签名):为了防止令牌被篡改,结合header和payload以及一个指定的密钥,通过特定算法生成。

应用场景举例:用于登录认证。

用户成功登录后,系统将生成一个令牌。此后,每个请求都需要附带该jwt令牌,并且系统会在处理每个请求之前进行拦截验证。

基于springboot使用JWT令牌

在pom文件中引入jwt依赖:

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

使用链式调用的方式来一步生成令牌

 public void enJwt(){
        HashMap<String, Object> claims= new HashMap<>();
        claims.put("id",1);
        claims.put("name","join");
        String jjweb = Jwts.builder()
                .signWith(SignatureAlgorithm.HS256, "jjweb")//指定数字签名的算法以及自定义的密钥类型,就是一个字符串
                .setClaims(claims)//第二部分,设置自定义数据,封装在map中
                .setExpiration(new Date(System.currentTimeMillis() + 3600 * 1000))//设置令牌有效期,一个小时内
                .compact();//调用后得到一个字符串返回值,即令牌
        System.out.println(jjweb);

    }

解释

创建 claims 对象

  • 我创建了一个名为“claims”的HashMap对象,其类型为HashMap<String, Object>,用于以键值对的格式存储要放入JWT令牌中的自定义数据。
  • 这里将两个键值对放入了 claims 中:
    • "id":1
    • "name":"join"
  • 这些数据通常作为JWT令牌的载荷部分,用于标识用户或存储其他相关信息。

生成令牌

使用 Jwts.builder() 来创建一个 JWT 构建器实例,生成一个新的 JWT 令牌。

设置自定义声明

  • signWith(SignatureAlgorithm.HS256, "jjweb"):使用 SignatureAlgorithm.HS256 指定哈希算法为 HMAC SHA-256,这是 JWT 常用的对称加密算法。
  • "jjweb" 是一个自定义字符串密钥,用于签名令牌。任何尝试验证此令牌的系统都需要知道这个密钥。签名用于验证数据完整性,确保数据在传输过程中没有被篡改。作为头部。

 添加claims声明对象

addClaims 是一个用于向现有的 JWT Builder 中添加多个声明(claims)的方法。这通常用于在生成 JWT 令牌时向其中添加自定义数据。

设置令牌的有效期

  • setExpiration(new Date(System.currentTimeMillis() + 3600 * 1000))
  • 使用 System.currentTimeMillis() 获取当前时间(以毫秒为单位),并加上 3600 * 1000(3600秒,即1小时)来指定令牌的有效期为1小时。一旦超过这个时间,JWT 就会被认为无效。

生成并返回 JWT 字符串

compact():调用 compact() 方法生成完整的 JWT 字符串。生成的 JWT 包含了以下三个部分,每部分用点(.)分隔:

  • Header(头部):通常声明令牌类型和签名算法。
  • Payload(载荷):包含声明的实际内容,如用户信息(claims)。
  • Signature(签名):基于 Header 和 Payload 以及密钥生成的签名,保证数据完整性和真实性。

项目中代码流程

提前封装好jwt工具类

此方法已自定义密钥和过期时间,并最终返回一个令牌。

 private static String signKey = "jjweb";
 private static Long expire = 52000000L;

    public static String generateJwt(Map<String, Object> claims){
        String jwt = Jwts.builder()
                .addClaims(claims)
                .signWith(SignatureAlgorithm.HS256, signKey)
                .setExpiration(new Date(System.currentTimeMillis() + expire))
                .compact();
        return jwt;
    }

Controller接收请求,调用service

@RequestMapping("/login")
public class LoginController {
    @Autowired
    private EmpService empService;
    @PostMapping
    public Result login(@RequestBody Emp emp){
        Emp emp1 = empService.login(emp);
        Result.success(emp1);
    }

Service处理层,调用数据访问层mapper接口

 @Override
    public Emp login(Emp emp) {
        Emp login = empMapper.login(emp);
        return login;

    }

Mapper数据访问层获取数据库中用户名和密码信息并映射到Emp对象中进行逐层返回

@Select("select * from emp where username=#{username} and password = #{password}")
    public Emp login(Emp emp);

Controller中对返回的Emp信息进行处理,并响应结果

如果登录成功,那么我们需要返回这个令牌

如果在数据库中查询到相关信息,那么emp对象将不为null。在这里,载荷部分使用了自定义信息,比如员工的id和姓名。最终,我们会对结果进行格式化处理后返回。如果没有找到信息,则返回错误信息。(不包含拦截验证,主要是生成并下发

 public Result login(@RequestBody Emp emp){
        Emp emp1 = empService.login(emp);
        //如果登录成功,就生成令牌,并发送给前端
        if(emp1!=null){
            HashMap<String, Object> claims = new HashMap<>();
            claims.put("id",emp1.getId());
            claims.put("username",emp1.getUsername());
            String jwt = JwtUtils.generateJwt(claims);
            return Result.success(jwt);
        }
        return Result.error("错误");
    }

使用postman进行本地测试

失败

c7ee49389fc94fbda95a02643b647d55.png

 成功

2eb50154afef474d8ee481a89ca8ef0a.png

请求拦截并验证JWT(下)icon-default.png?t=N7T8https://mp.csdn.net/mp_blog/creation/editor/141750536

C你太美,一种多看一眼就会爆炸的代码艺术icon-default.png?t=N7T8https://blog.csdn.net/2301_81243054/article/details/141663587

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值