JWT的简单说明(含案例代码)

参考文章 : https://www.bilibili.com/video/BV1i54y1m7cP?p=1
看了b站up 主编程不良人 的JWT的视频后做的笔记,若想看原视频,请点击上面的参考文章


1.什么是JWT

官方说明:
  JSON Web令牌(JWT)是一个开放标准(RFC 7519),它定义了一种紧凑且自包含的方式,用于将信息作为JSON对象在各方之间安全地传输。可以对该信息进行验证和信任,因为它是数字签名的。jwt可以使用秘密(使用HMAC算法)或使用RSA或ECDSA的公钥/私钥对进行签名。


通俗的说:
   JWT的全称是JSON Web Token,它是开源的,通过json的形式作为web应用中的令牌,可以安全的以json的形式传输数据。在传输过程中,可以完成数据的加密与签名等。


2.JWT能做什么

2.1.授权

  当访问的页面需要令牌时,若前端发送请求时没有携带令牌,或者令牌信息被篡改了,后端系统都不能通过验证令牌,所以就不会转发到访问的页面。比如说需要用户登录才能访问的页面,就需要携带令牌。


2.2.信息交换

  当系统A与系统B需要数据交换时,就可以用JWT来进行信息交换,以保证数据的安全,防止被篡改。因为系统每次都会检验令牌,校验不通过,系统就不使用该信息。


3. 为什么是JWT

3.1.传统的session认证

  我们知道http协议是无状态的,即当链接建立完成后,就会断开,当需要记录一些状态时(比如登录状态),就会出现问题,因为是无状态的,他不能长期存储一些信息。因此当客户端需要访问一些需要登录成功后才能访问的页面,服务器就不能知道用户是否登录了,因此就出现了session机制。
  有了session后,当我们登录后,服务器就会生成一个session,并保存到服务器内存中,然后再以cookie的形式将这个session发送给客户端,cookie的key是sessionid,value就是session的值,这样客户端就有了一个状态了,在之后客户端每次发送请求的时候,就可以在请求头的cookie中携带该session的信息以访问有保护的页面。

在这里插入图片描述

缺点:

  1. 因为session是保存在内存中的,当用户数量一多了之后,就会耗费服务器极大的资源
  2. 因为session是记录在一台服务器机上面的,当需要做分布式的时候,还需要完成session的共享,增大系统复杂度
  3. 因为是基于cookie进行用户识别的,如果cookie被截获,用户就很容易受到跨域请求伪造攻击,很不安全

3.2.JWT认证

在这里插入图片描述
认证流程:

  1. 用户输入用户名、密码登录,后端系统认证通过后会生成一个JWT,然后将这个令牌响应给客户端,让其保存到本地
  2. 客户端需要请求被保护的页面时,可以携带该令牌发送请求,后端系统会进行校验,若校验通过,放行资源,响应数据;若校验失败,则会返回错误信息,让用户进行登录

优点:

  1. JWT会进行加密处理后保存在客户端,因此是安全的
  2. 不需要在服务器保存会话信息,使用与分布式系统

4.JWT的结构

4.1. 组成

  JWT是由三段结构组成的,分别是标头(Header)、有效载荷(Payload)、签名(Signature)。这三段结构的json格式,然后再加密,就会得到JWT,因此JWT的格式如下:xxxx.yyyy.zzzz


4.2.Header

  标头由两部分组成:令牌的类型(默认为JWT) 和 JWT加密所使用的算法(如HMAC、SHA256、RSA),然后再使用 Base64 编码,构成JWT的第一部分。格式如下:

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

4.3.Payload

  有效负载是存放用户数据的声明,然后再使用 Base64 编码,构成JWT的第二部分。因此,千万能存放用户的敏感信息,因为别人是能解码看到你的敏感信息。格式如下:

{
	"id":"123",
	"name":"Xavier",
	"status":"yes"
}

标准中的负载声明:

iss:Issuer,jwt签发者(生产者)
sub:Subject,jwt面向的用户(消费者)
aud:Audience,接受jwt的一方
iat:IssuedAt,jwt的签发时间
exp:ExpiresAt,jwt的过期时间,这个时间必须大于签发时间
nbf:NotBefore,定义在什么时间之前,该jwt都不是不可用的
jti:JWTId,jwt的唯一身份标识,主要用作一次性token,从而回避重放攻击

4.4. Signature

  签名是使用前面两个json信息的 Base64 编码,再加一个盐值,最后再使用Header中指定的算法进行加密。


签名目的:
  防止信息被篡改。若有人对头部和负载的内容解码后再进行修改,再进行编码,最后再加上之前的签名组成新的JWT的话,那么服务器是无法识别该JWT的,因为篡改后的头部和负载的新签名与原来的签名是绝对不可能一样的。若对新头部和负载内容进行签名,在不知道服务器的 密钥(盐值)的情况下,是绝对得不服务器到能验证通过的值。


最终效果:

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
.eyJ1X2lkIjoxMjMsImV4cCI6MTYyMDAyNDY3OCwidXNlcm5hbWUiOiJYYXZpZXIifQ
.4i3di0tXbRgRLpPIU9GRk3vBQf-13_yDZzxJl8O6CKQ

5.JWT使用

依赖:

<dependency>
    <groupId>com.auth0</groupId>
    <artifactId>java-jwt</artifactId>
    <version>3.15.0</version>
</dependency>

简单使用:

public class JWTTest {
    private String sing = "asd@!#987@#!#";          //盐值

    /**
     * 生成JWT
     */
    @Test
    public void contextLoads() {
        Calendar instance = Calendar.getInstance();
        instance.add(Calendar.DATE, 7);
        String token = JWT.create()
                .withClaim("u_id", 123)     //payload
                .withClaim("username", "Xavier")
                .withExpiresAt(instance.getTime())      //超时时间
                .sign(Algorithm.HMAC256(sing));         //签名(加密)
        System.out.println(token);
    }

    /**
     * 验证JWT,并获取其信息
     */
    @Test
    public void verify(){
        JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(sing)).build();
        DecodedJWT verify = jwtVerifier.verify("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1X2lkIjoxMjMsImV4cCI6MTYyMDYzMDA2NCwidXNlcm5hbWUiOiJYYXZpZXIifQ.zTIeb7yJb1cKk1o7qCRiozcPafOdE7oln7cuJQZHcMA");
        Integer u_id = verify.getClaim("u_id").asInt();
        String username = verify.getClaim("username").asString();
        System.out.println(u_id);
        System.out.println(username);
    }
}

异常类型:

AlgorithmMismatchException			算法不匹配异常
SignatureVerificationException 		签名不一致异常
TokenExpiredException				令牌过期异常
InvalidclaimEkception				失效的payload异常

JWT验证流程:

  1. 验证算法
  2. 验证签名
  3. 对JWT解密
  4. 验证过期时间或payload

6.代码实战

GitHub代码地址:https://github.com/Xavier-777/jwt

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
以下是一个简单的 Spring Cloud Gateway 基于JWT的验证代码案例: 1. 首先,确保你的项目中已经引入了相关的依赖,包括 Spring Cloud Gateway、Spring Security 和 JWT 相关的库。 2. 创建一个自定义的 GatewayFilter,用于验证JWT并将用户身份信息添加到请求头中: ```java import org.springframework.cloud.gateway.filter.GatewayFilter; import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.http.HttpHeaders; import org.springframework.stereotype.Component; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; @Component public class JwtAuthFilter implements GatewayFilter { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { // 从请求头中获取 JWT String jwt = exchange.getRequest().getHeaders().getFirst(HttpHeaders.AUTHORIZATION); // 验证 JWT,根据需要进行相应的验证逻辑 // 如果验证成功,将用户身份信息添加到请求头中 exchange.getRequest().mutate() .header("X-User-Id", "123") // 示例,替换为实际的用户身份信息 .build(); return chain.filter(exchange); } } ``` 3. 在配置类中注册自定义的 GatewayFilter: ```java import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class GatewayConfig { @Bean public JwtAuthFilter jwtAuthFilter() { return new JwtAuthFilter(); } } ``` 4. 配置 Spring Cloud Gateway 路由谓词和过滤器,指定需要进行JWT验证的路由: ```yaml spring: cloud: gateway: routes: - id: example_route uri: http://example.com predicates: - Path=/example/** filters: - JwtAuthFilter= # 指定使用 JwtAuthFilter 进行JWT验证 ``` 在这个示例中,我们创建了一个名为 `JwtAuthFilter` 的自定义过滤器,用于验证JWT并将用户身份信息添加到请求头中。然后在配置类中注册该过滤器,并在路由配置中指定需要使用该过滤器的路由。 请注意,这只是一个简单的示例,实际的JWT验证逻辑可能更复杂。你可以根据自己的需求进行相应的调整和扩展。希望对你有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值