JWT !


前记:

  • 官网:https://jwt.io/
  • jwt有人说是用计算力换空间(相对于session)
  • 小程序后台要求全部用springboot实现.。登录状态的管理:本来想用自己随便生成UUID作为token使用,然后token可以配合cookie进行存储与传送。但是微信小程序发起的请求中默认不带有cookie(可以通过设置来发出cookie,但麻烦),同时为了更方便与更安全,则学习JWT。
  • 学习视频:https://www.bilibili.com/video/BV1i54y1m7cP?from=search&seid=14084425364989447981

一、概述

  1. JWT:json web token :JSON Web令牌

  2. 作用:

    • 授权
    • 信息交换(签名处理)
  3. 传统的session认证

    1. 认证方式与流程

      • 客户端发来请求
      • 服务端生成session对象**(保存在服务器内存中)**,保存用户一些信息
      • 服务端生成sessionid放在cookie的 Jsession 字段中返回给用户
      • 用户下次请求的时候,在cookie中带有 Jsession,作为认证
    2. 暴露的问题
      • session保存在服务器内存中,如果用户量大,服务端的开销大
      • 会话如果保存在一个服务器上,在分布式系统中,用户必须访问同一个服务器,限制了负载均衡器的能力,限制了扩展能力
      • 基于cookie认证,如果cookie被截获,容易受到跨站请求伪造攻击
      • 在前后端分离的系统中,增加了部署的复杂性。通常用户一次请求就要转发多次,如果用session,每次携带sessionid到服务器,服务器还要查询用户信息,增加负担 (??看不懂)
  4. JWT认证

  1. 认证流程

    • 前端发来账号密码认证请求

    • 后端核对成功后,将用户id等其他信息作为 JWT Payload,将其与头部分别进行Base64编码拼接后签名,形成一个JWT。

    • 前端收到响应后,将jwt保存在本地

      以后:

    • 前端的每次请求,在HTTP Header中的Authorization字段中放入 JWT(解决XSS和XSRF)

    • 后端检查JWT合法性,包括是否存在,有效性,签名合法性,接收方是否自己等

    • 后端验证成功后,用JWT包含的用户信息进行其他操作,返回结果

  2. 优势

    • 简洁:可以通过URL、post参数在HTTP header中改善,数据量小,传输速度快
    • 自包含self-contaioned:负载中包含了所有用户所需要的信息,避免多次查询数据库
    • Token是以json加密的形式保存在客户端的,所以JWT是跨语言的,原则上任何web形式都支持
    • 不需要在服务商保存会话信息,节约服务端内存开销,且特别适用于分布式系统的开发
    • 服务器断电后,只要token不过期,那么token还有效!

二、结构

JWT的结构由三部分组成:

  • 标头Header
  • 有效载荷Payload
  • 签名Signature

格式: xxxx(header 的base64编码) . yyyy(payoad的base64编码) . zzzz(签名)

标头Header

  1. 标头由两个部分组成: 令牌类型(JWT) + 所使用的签名算法

  2. 用Base64进行编码(所以可被解码)

  3. 格式:

    {"alg": "HS256",  #表示所使用的签名算法"typ": "JWT"    #表示令牌类型
    }
    

有效载荷

  1. 包含声明。声明是有关实体(如用户)等其他数据的声明

  2. 用Base64进行编码(所以可被解码)

  3. 一般情况下不能放如密码等敏感的信息

  4. 其实可以把实体信息加密码后,才放入Payload中

  5. 格式:

    {"userID": "1234543536",   #后台自定义的一些消息"name": "admin","sex": "男"
    }
    

签名

  1. 使用编码后的header和Payload以及私钥,再使用header中指定的编码进行签名
  2. 目的:保证 JWT 在传输过程中没有被篡改过
  3. 验证流程:对前端送来的JWT,取前面两个字段(header和payload),再用私钥,再用header中指定的编码进行签名的生成,将生成的签名与前端送来的JWT的第三个字段进行对比,相同则证明没有被篡改过

三、JWT在java使用

依赖:

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

编码形成token

设置的过期时间会在payload中增加一个exp字段(第二个java程序中输出可以看出)。

所以这就是为什么xxx.yyy.zzz中签名字段加签的时候没有用到时间,但结果还是体现出了和时间相关

    @Testvoid contextLoads() {Calendar calendar = Calendar.getInstance();calendar.add(Calendar.SECOND, 6000);//设置6000sString token = JWT.create()// .withHeader(new HashMap<>())  //添加标头,不写默认 jwt 和 HS256.withExpiresAt(calendar.getTime())//设置过期时间,注意:签名的值与过期时间相关!!!.withClaim("userName", "hao")//设置payload中的声明块.withClaim("userID", 123).sign(Algorithm.HMAC256("我是私钥"));//设置签名的算法和私钥System.out.println(token);}
/**输出:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2MTc3MTg5MjAsInVzZXJOYW1lIjoiaGFvIiwidXNlcklEIjoxMjN9.CCrsWH0XWTDqUVxE94sL4ABBuBGmRuco5AUPxSurQAY
**/

对已有的token进行解码

    @Testvoid test() throws IOException {Verification verification = JWT.require(Algorithm.HMAC256("我是私钥"));//指定验证签名时的算法及私钥DecodedJWT decodedJWT = verification.build().verify("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9." +"eyJleHAiOjE2MTc3MTg5MjAsInVzZXJOYW1lIjoiaGFvIiwidXNlcklEIjoxMjN9." +"CCrsWH0XWTDqUVxE94sL4ABBuBGmRuco5AUPxSurQAY");//对指定的token进行验证System.out.println("token = " + decodedJWT.getToken());//拿到一整个tokenSystem.out.println("header = " + decodedJWT.getHeader());//拿到base64编码的标头System.out.println("解码后:" + new String(new BASE64Decoder().decodeBuffer(decodedJWT.getHeader())));System.out.println("payload = " + decodedJWT.getPayload());//拿到base64编码的payloadSystem.out.println("解码后:" + new String(new BASE64Decoder().decodeBuffer(decodedJWT.getPayload())));System.out.println("signature = " + decodedJWT.getSignature());//拿到签名System.out.println("userName = " + decodedJWT.getClaim("userName").asString());//拿到payload中的声明块字段的值System.out.println("userID = " + decodedJWT.getClaim("userID").asInt());}/**输出:
token = eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2MTc3MTg5MjAsInVzZXJOYW1lIjoiaGFvIiwidXNlcklEIjoxMjN9.CCrsWH0XWTDqUVxE94sL4ABBuBGmRuco5AUPxSurQAYheader = eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
解码后:{"typ":"JWT","alg":"HS256"}payload = eyJleHAiOjE2MTc3MTg5MjAsInVzZXJOYW1lIjoiaGFvIiwidXNlcklEIjoxMjN9
解码后:{"exp":1617718920,"userName":"hao","userID":123}signature = CCrsWH0XWTDqUVxE94sL4ABBuBGmRuco5AUPxSurQAY
userName = hao
userID = 123
**/

四、工具类的封装

/**
对第三大点进行简单的封装
**/
public class JWTUtil {private final String KEY = "我是私钥";public static String getToken(Map<String, String> claimMap) {Calendar calendar = Calendar.getInstance();calendar.add(Calendar.SECOND, 6000);//设置6000sJWTCreator.Builder jwtBuilder = JWT.create();
//        claimMap.forEach(jwtBuilder::withClaim);    //两种lambda表达式都可以
//
//        claimMap.forEach((k,v)->{//            jwtBuilder.withClaim(k,v):
//        });for (Map.Entry<String, String> entry : claimMap.entrySet()) {jwtBuilder.withClaim(entry.getKey(), entry.getValue());}String token = jwtBuilder.withExpiresAt(calendar.getTime()).sign(Algorithm.HMAC256(KEY));return token;}//调用的方法需要在外部try catch, 拿到异常。无异常则正常public static void verify(String token) {JWT.require(Algorithm.HMAC256(KEY)).build().verify(token);}
}

五、配合拦截器

关于token在项目中的理解:

@Component
public class CommonInterceptor implements HandlerInterceptor {@Autowiredprivate RedisService redisService;@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {String token = request.getHeader("token");//token要放在header中if (token == null) {return false;}if (redisService.get(token) == null) {  //如果redis没有这个tokenreturn false;}try {JWTUtil.verify(token);} catch (Exception e) {  //接住JWT工具封装的异常return false;}return true;}
}
    @PostMapping("/login")public String login(@RequestBody Map<Object, Object> data,HttpServletResponse response) {System.out.println("执行了登录接口");//从云函数返回的resultBean中拿到dataJSONObject resultBeanJsonObject = JSON.parseObject(cloudFunction.execute("admin", JSON.toJSONString(data)));JSONObject dataJsonObject = resultBeanJsonObject.getJSONObject("data");String id = dataJsonObject.getString("_id");String admin = dataJsonObject.getString("admin");Map<String, String> claimMap = new HashMap<>();claimMap.put("id", "id");claimMap.put("admin", admin);String token = JWTUtil.getToken(claimMap);dataJsonObject.put("token", token);//放入返回数据data中resultBeanJsonObject.put("data", dataJsonObject);//把data更新到resultBean中String oldToken = redisService.get(id);if(oldToken != null) {//如果上次登录时的token还在,则移除,防止用户多次登录爆redis内存redisService.remove(oldToken);redisService.remove(id);}
//反向两个key其实有两个功能:
//1:可以防用户重复登录时,redis爆内存。因为上一次的旧token(上一次登录时的token),会被清除。
//2:可以让用户只能在一个设备上登录。因为在另一个设备上登录时,旧的token(另一台设备上存的)会被从redis中清除redisService.setWithExpire(token, id, RedisConstant.TOKEN_EXPIRE);//加入redisredisService.setWithExpire(id, token, RedisConstant.TOKEN_EXPIRE);//加入反向key,防止用户多次登录爆redis内存return resultBeanJsonObject.toJSONString();}

JWT|概述|JWT结构|JWT在java中的使用|JWT工具类的封装|JWT在springboot中的使用|JWT与拦截器的配合相关推荐

  1. java常用工具类_java(二):工作中常用到的工具类

    工作中大家要用到很多工具类,第三方的jar中有很多现成的工具类符合自己的项目需要,这个时候就不需要去重复造轮子了,从而节省了很多时间,大家可以利用这些时间去做其它重要的事情,如果没有符合自己的工具类, ...

  2. java.lang包有哪些类_Java中Lang包的工具类有哪些

    Java中Lang包的工具类有哪些 发布时间:2020-12-08 16:15:36 来源:亿速云 阅读:76 作者:Leah 今天就跟大家聊聊有关Java中Lang包的工具类有哪些,可能很多人都不太 ...

  3. java中定义一个CloneUtil 工具类

    其实所有的java对象都可以具备克隆能力,只是因为在基础类Object中被设定成了一个保留方法(protected),要想真正拥有克隆的能力, 就需要实现Cloneable接口,重写clone方法.通 ...

  4. java运行python脚本_java中执行python脚本工具类详解

    java中执行python脚本工具类,需要jython.jar import java.io.FileInputStream; import java.io.IOException; import j ...

  5. java中常用的日期工具类

    java中常用的日期工具类 日期相关的类: package net.yto.ofclacct.core.util;import java.text.ParseException; import jav ...

  6. OkHttp工具类在微服高并发场景中问题实践总结

    OkHttp工具类在微服高并发场景中问题实践总结 问题场景 我的应用是一个中间业务应用XXApp,一个交易请求进来需要依赖下游应用,采用http协议通讯方式,需要调用3-4次下游请求. 老XXApp在 ...

  7. java录排名怎么写_面试官:Java排名靠前的工具类你都用过哪些?

    你知道的越多,不知道的就越多,业余的像一棵小草! 你来,我们一起精进!你不来,我和你的竞争对手一起精进! 编辑:业余草 推荐:https://www.xttblog.com/?p=5158 在Java ...

  8. java inputtools_Java后台开发常用工具类

    本文涉及的工具类部分是自己编写,另一部分是在项目里收集的.工具类涉及数据库连接.格式转换.文件操作.发送邮件等等.提高开发效率,欢迎收藏与转载. 数据库连接工具类 数据库连接工具类--仅仅获得连接对象 ...

  9. java 兼容excel_Java解析Excel工具类(兼容xls和xlsx)

    依赖jar org.apache.poi poi-ooxml 4.0.1 ExcelUtils.java package javax.utils; import java.io.File; impor ...

最新文章

  1. 手机客户端和web端开发的异同
  2. NetTiers中的一些内置对象及关系
  3. Spring.NET学习笔记(4)-对象作用域和类型转换
  4. yuki翻译器钩子_git hooks钩子
  5. ubuntu16.04下安装mysql详细步骤
  6. Teamcenter 入门开发系列问答(1)
  7. 卡西欧计算机怎么传程序,卡西欧计算器程序传输软件fa-124的使用方法
  8. mayaa的一些代码
  9. centos7.2 kvm 安装超详细
  10. 关于git和SVN的介绍和区别
  11. PHP如何关闭notice级别的错误提示
  12. adb命令 关机与重启
  13. 卷积神经网络原理详解
  14. WebLogic安装教程
  15. 天地图API 调用影像底图 影像注记 全球境界
  16. 你知道 1 + 1 等于几吗?
  17. 柱状图柱子上面显示数字
  18. 计算机玩什么游戏都闪退,电脑玩原神闪退怎么办 原神PC版闪退解决方法
  19. 计算机 语言学 交叉,计算机和语言学
  20. 关于大学生课余时间分配利用的调查报告

热门文章

  1. 关于MessageBox与天鹰网络战队XiaoXi系列函数的使用说明
  2. Linux网卡驱动适配各个内核,网卡驱动8 MII接口以及linux内核对MII的支持
  3. Kylin 在满帮集团千亿级用户访问行为分析中的应用
  4. java wrapper怎么运行_java wrapper方式部署项目
  5. 输入起始日期,截止日期,查询天数
  6. 股票的委托价、成交价与成本价的关系
  7. Ettercap安装教程
  8. OpenGL基础图形编程(八)变换
  9. VR校园欺凌安全教育系统进入校园|广州华锐互动
  10. 数学建模——时间序列模型及spss实现