浅析JWT| JWT是啥子,Java构建JWT

116 阅读6分钟

本文出自——可乐可乐可,作者主页链接:可乐可乐可的个人主页

小声bbb

说到系统的安全识别,记得自己第一个项目,用的就是session,用户登录进来以后,给他session标记登录,记录id进去,轻轻松松,设计的操作也很简单,类似操作HashMap。 这大概也有1年多快两年了,现在回头看真的是可怕,几乎在裸奔

众所周知,平常使用的Session是存储在服务器的一种技术,可以理解为一个会话id,每次使用HTTP请求,都会携带一个sessionId,服务器根据这个SessionId去找对应的session

session一遍是和cookie搭配使用的,cookie是不安全的,毋容置疑(很多浏览器没限制读取),session则是系统生成的一个较长的sessionId,在过期时间内破解session比较困难。 关于session安全性文章,搜一下csdn,很多的 Session安全性

しかし,我预判了你的预判

在这里插入图片描述

Session可以理解为是存储在服务器端,key叫sessionId的一个map结构。 Session类似于打电话(没有来电号码显示),在一开始你表明了自己的身份,通话结束后,就失去了效果(实际上使用的是过期的手段)。 当访问的数量增加,记录登录成为一个很大的压力(有记录,有过期操作等,每个人的session信息都要进行维护,且需要存储),是否有一种服务器不用操心的办法? 那么下面就是JWT(或者叫Token)发光发热的舞台了!

在这里插入图片描述

只是为了构建JWT请快步到目录相应的位置

啥是JWT

JWT的全称JSON Web Token 在这里插入图片描述这里我先简单说一下JWT是个啥东西,然后分析为什么好用 JWT可以看做一个身份证, 众所周知,身份证有这几个特性:

  • 身份证不能伪造(别动歪脑筋)
  • 身份证上有个人信息
  • 身份证上有签发机关
  • 身份证上有有效期

事实上,这几乎就是JWT了

JWT的特性完全相同,甚至可以用理解身份证的角度来理解他

  1. 你的网站签发一个令牌(跟我念:身份证)
  2. 客户端拿着这个令牌找你访问
  3. 你用你三岁就发明的识别机对令牌(身份证)识别
  4. 你已经明白他是自己人了,并邀请他一起进来看电视
  5. 以下为收费项目~~

在这里插入图片描述咳咳,不搞hs,回到正轨,通过我们一本正经的分析, 我们不难发现:Token可以做到在你脸前裸奔,但你却无可奈何 盘点主要特性:

  • 存储简单的信息,并且大家都能获取信息
  • 无法作假
  • 存在过期

其中第一点很重要,token里面的信息是公开的,所以别放密码.

这里插一嘴,jwt里面的信息确实是公开的,只不过大家都进行了二次加密,让人感觉好像jwt里面的信息是不公开的

@某大学某实验室的某学弟

细说JWT

JWT通常情况下是三段,但是也存在一些丧心病狂的,把token又加密了一遍(内行,我直呼内行) 下面是官方给的一个demo(例子) 这个网站也是可以访问的,可以自己试着玩,也可以用来测试 jwt.io/ 在这里插入图片描述其中很明显为三个部分:HEADER(头部)、PAYLOAD(数据)、VERIFY SIGNATURE(签名)

  • 头部:这个token使用了什么加密算法
  • 数据:自己定的,想塞什么塞什么,一般有规定的几个内容
  • 签名:可以理解为使用秘钥加密后得到的一个不可逆加密(存密码用的很多,原理类似)

其中数据(PAYLOAD)官方定了这几个部分:

    iss (issuer):签发人
    exp (expiration time):过期时间
    sub (subject):主题
    aud (audience):受众
    nbf (Not Before):生效时间
    iat (Issued At):签发时间
    jti (JWT ID):编号

签名(Signature )部分是对前两部分的签名,防止数据篡改。

首先,需要指定一个密钥(secret)。这个密钥只有服务器才知道,不能泄露给用户。然后,使用 Header 里面指定的签名算法(默认是 HMAC SHA256),按照下面的公式产生签名。

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)

算出签名以后,把 Header、Payload、Signature 三个部分拼成一个字符串,每个部分之间用"点"(.)分隔,就可以返回给用户。

JWT 的几个特点

上面用比较形象的方式描述了JWT,下面用官方的话来总结特点

  1. JWT 默认是不加密,但也是可以加密的。生成原始 Token 以后,可以用密钥再加密一次。
  2. JWT 不加密的情况下,不能将秘密数据写入 JWT(个人认为加密了也最好别加吧,秘密的东西最好保持在用后即毁的状态)。
  3. JWT 不仅可以用于认证,也可以用于交换信息。有效使用 JWT,可以降低服务器查询数据库的次数。
  4. JWT 的最大缺点是,由于服务器不保存 session 状态,因此无法在使用过程中废止某个 token,或者更改 token的权限。也就是说,一旦 JWT 签发了,在到期之前就会始终有效,除非服务器部署额外的逻辑(用缓存保存一次签发出去的JWT)。
  5. JWT 本身包含了认证信息,一旦泄露,任何人都可以获得该令牌的所有权限。为了减少盗用,JWT的有效期应该设置得比较短。对于一些比较重要的权限,使用时应该再次对用户进行认证。
  6. 为了减少盗用,JWT 不应该使用 HTTP 协议明码传输,要使用 HTTPS 协议传输。

现在来完成一个JWT的实现

详细大家都有maven的经验了

实在不会可以去maven仓库把jar包下载

你用你三岁时就买来的键盘,轻松的使用这个jjwt框架,并老老实实的按照我给的流程感♂受

第一步,导入maven

<!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt -->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.1</version>
        </dependency>

第二步,编写Token的生成逻辑

public static String tokens(Map<String, Object> claims, String secretKey, int millisecond, String jwtIssuer, String jwtAud) {

       //获取当前的时间
       Calendar calendar = Calendar.getInstance();
       Date date = new Date(System.currentTimeMillis());
       calendar.setTime(date);
       //向后退后秒数
       calendar.add(Calendar.MILLISECOND, millisecond);
       Date endTime = calendar.getTime();
       JwtBuilder builder = Jwts.builder().setClaims(claims)
               .signWith(SignatureAlgorithm.HS256, secretKey)
               .setClaims(claims)
               .setIssuedAt(new Date())
               .setExpiration(endTime)
               .setIssuer(jwtIssuer)
               .setAudience(jwtAud);
       return builder.compact();
   }

JwtBuilder 是jjwt提供的工具,可以很轻松的构建出一个jwt,利用Builder设计模式,对内容进行定义 其中payload的自定义内容是使用map保存的

编写解密验证的逻辑

public static Claims parse(String jwt, String secretKey) throws JwtExpireException, JwtVerifyException , JwtNotExistException{
       Claims claims = null;
       try {
           claims = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(jwt).getBody();
       } catch (ExpiredJwtException expiredJwtException) {
           throw new ExpiredJwtException("token过期");
       } catch (JwtException jwtException) {
           throw new JwtException("JWT验证错误");
       } catch (IllegalArgumentException illegalArgumentException) {
           throw new IllegalArgumentException("Token为空");
       }
       return claims;
   }

Claims类就是你的PAYLOAD,可以直接取出信息使用,不抛出异常就视为成功了,如果希望信息隐藏,使用自己的秘钥二次加密即可。

一键三连,支持弟弟

在这里插入图片描述写到这里,就完成了基础的内容了,为了我们用起来更爽, 可以自行进行二次封装,体验更棒