JWT创建与验证

一、什么是JWT?

     jwt全称为jsonwebtoken,它是一个开放标准(rfc7519),它定义了一种紧凑的、自包含的方式,用于在各方之间以JSON对象安全地传输信息.此信息可以验证和信任,因为它是数字签名的.jwt可以使用HMAC算法或RSA或ECDSA的公钥/私钥对进行签名.

二、JWT的作用

1、授权

       这是使用JWT的最常见方案,一旦用户登录,每个后续请求将包含JWT,从而允许用户访问该令牌允许的路由,服务和资源,单点登录时当今广泛使用JWT的一项功能,因为它的开销很小并且可以在不同的域中轻松使用.

2、信息交换

      JWT是在各方之间安全的传输信息的好方法,因为可以对JWT进行签名,使用表头和有效负载以及自定义标签计算,因此不仅可以验证请求方是否可访问,还可以验证内容是否被篡改.

三、为什么要使用JWT?

     1、传统的Session登录验证方式通常需要将用户id或用户姓名以及权限等信息存储在Session中便于后续业务开发,这样做的代价就是会消耗大量服务器的内存资源,因为在浏览器访问服务器时,若请求中携带了SeesionId,则服务器会根据这个SessionId来查询对应的Session,若查找成功,则从中提取信息,若查找为空,则创建一个Session,并将id存入cookie中响应给浏览器.因此在浏览器与服务器中都需要消耗资源存储Session,若在线用户量较大,则内存压力很大,此时通常会选择构建服务器集群的方式来缓解压力(当然也有其他方式).

    2、如上所述,构建集群缓解内存压力,但此时又会引出一个新的问题,不同服务器之间的Session如何共享呢?因为如果Session不共享,那么在A服务器登录后,下次请求时被分配到B服务器,那么B服务器中并不存在登陆后所创建的Session,难道要用户再次登录吗?这肯定不合理,因此需要实现Session共享,此时一般都会选择利用缓存中间件,如Redis来记录登录状态,利用key-value数据存储,此方法较为可行,读取速度也快,也能有效设置过期时间,但如果Redis宕机了呢?这时有人可能会提出Redis集群的方式来保证可靠性,但如果极端情况下,都宕机了怎么办,系统就直接宣告崩溃吗?

(当然也有其他方式,例如:

(1)、将存储在服务端的session保存在客户端cookie中,按照自定义的加密规则将session数据加密保存到cookie中:
优点:服务器压力减小,同时能够解决在多个服务器之间session不共享的问题。
缺点:不同的浏览器对cookie容量有大小限制;客户端每次请求都需要通过cookie发送session数据给服务器,导致网络请求占用高。
该方案不适合高访问量:带宽性能消耗大。

(2)、Session存入数据库中实现共享

建议使用内存表Heap进行存储
优点:安全性好。
缺点:(1)自己需要实现session淘汰逻辑;
           (2)进行高并发读写时,数据库性能将会成为瓶颈,且容易出现表锁。

(3)、基于NFS的Session共享

多台运行服务器共享保存session文件的磁盘。
优点:实现简单,仅需将共享目录服务器mount到各频道服务器的本地session目录。
缺点:NFS依托于复杂的安全机制和文件系统,因此并发效率不高,尤其对于session这类高并发读写的小文件, 会由于共享目录服务器的io-wait过高,最终拖累前端WEB应用程序的执行效率。

     3、CSRF(跨站伪造请求攻击)很难解决

   session是基于cookie进行用户识别的,cookie如果被截获,用户就会很容易收到跨站请求伪造的攻击,用户信息容易泄露,同时也可能对系统造成破坏.

     4、移动端设备session特性

 移动端设备访问网站时,IOS/Android用原生接口发请求最大的特点是每一次请求创建一个会话,那么session用于登录验证自然也就无用了.

        为了解决上述问题,JWT应运而生.JWT所生成的令牌是存储在客户端的,这样解决了服务端内存消耗以及信息共享的问题,同时也解决了CSRF攻击隐患,因为服务端可以判断令牌内容是否被篡改,对于移动端设备session特性,都不采用session了,自然不用考虑这个问题.是不是感觉JWT验证非常nice呢!

四、JWT的结构

1、JWT令牌组成

 (1)、表头(Header)

 (2)、有效负载(Payload)

 (3)、签名(Signature)

  因此,JWT通常如下所示:xxxxx.yyyyy.zzzz  Header.Payload.Signature

2、Header

      标头通常由两部分组成:令牌的类型(即JWT)和所使用的签名算法.它会使用Base64编码组成JWT结构的一部分,默认情况下一般为{ “alg":"HS256", "typ":"JWT"},需要注意的是,Base64仅仅是一种编码,因此也可以解码,所以它并不是一种加密过程.

3、Payload

     令牌的第二部分是有效负载,其中包含声明,声明是有关实体(通常是用户)和其他数据的声明.同样的,它也会使用Base64编码组成JWT结构的第二部分,例如{ "userid":"1","username":"zhangan"},因此在服务端构建jwt时,可以使用哈希表传参.但负载并没有采取加密,所以不应放置用户密码等敏感信息.

4、Signature

     前面两部分都是使用Base64进行编码的,即前端可以解析信息,Signature需要使用编码后header和payload以及我们提供的一个密钥,然后使用header指定的签名算法进行签名,签名的作用是保证JWT没有被篡改过.

签名目的:最后一步签名的过程,实际上是对头部以及负载内容进行签名,防止内容被篡改,如果有人对头部以及负载的内容解码之后进行修改,再进行编码,最后加上之前的签名组合形成新的JWT的话,那么服务端就会判断出新的头部和负载形成的签名和JWT附带上的签名是不一样的.如果要对新的头部和负载签名,在不知道服务器加密时用的密钥的话,的出来的签名也是不一样的.

服务端返回的内容为三个由点分割的Base64-URL字符串,可以在HTML和HTTP环境中轻松传递这些字符串,与基于XML的标准相比,它更为紧凑与简洁,可以通过URL,POST参数或者在HTTP header发送,因为数据量小,传输速度快,负载中也可以包含用户信息,避免了多次查询数据库.

五、创建方式

1、引入jwt依赖

<dependency>
  <groupId>com.auth0</groupId>
     <artifactId>java-jwt</artifactId>
     <version>3.8.2</version>
</dependency>
<dependency>
     <groupId>io.jsonwebtoken</groupId>
     <artifactId>jjwt</artifactId>
     <version>0.9.1</version>
</dependency>

2、封装工具类


import io.jsonwebtoken.*;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.Map;

@Component
public class JWTUtils {
    private static final String SIGNAL="!TEST%2002@YUSHEN&&XIAOYU#login";
    public String getToken(Map<String,Object> map)  {
        JwtBuilder jwtBuilder= Jwts.builder();//获取JWT构造器
        String token=jwtBuilder.setIssuedAt(new Date())  //设置jwt生成时间
                .setClaims(map) //可以存放用户姓名、id此类便于后续业务开发的信息,不要存放密码等敏感信息
                .setExpiration(new Date(System.currentTimeMillis()+5000))  //设置token有效期
                .signWith(SignatureAlgorithm.HS256,SIGNAL)  //设置token加密方式和密钥
                .compact(); //生成token字符串
        return token;
    }
    public Claims check(String token){
        if(null==token||"".equals(token)) throw new RuntimeException("无token");
        //获取jwt解析器
        JwtParser parser = Jwts.parser();
        parser.setSigningKey(SIGNAL);//指定解析密钥
        Jws<Claims> claimsJws = parser.parseClaimsJws(token);
        return claimsJws.getBody();
    }
}

3、一般JWT验证会配合拦截器使用

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值