手写jwt验证,实现java和node无缝切换
前言
前端时间和我朋友写了一个简易用户管理后台,功能其实很简单,涉及到的技术栈有:vue+elementUI,java+spring MVC以及node+egg,数据库用的mysql,简单方便。
一开始是我是只负责前端,但是前端开发的的速度太快,老是没事,加上他小子并没有接触过实战的项目,又怕他出乱子,所以考虑我也写一个后端,
开始考虑的是用python+django,但是还是在半途放弃了,因为总感觉Django不过灵活,使用起来非常别扭,也可能是用scrapy写爬虫写多了,难以理解django的框架设计,总是会把他想象成一个scrapy架构,也导致代码写的很乱,下面上一张scrapy架构图。
所以最后考虑的用node,Express和Koa框架学习过node应该都知道,我以前也用过express(写过一个小demo),但是给我的感觉这到像是一个只能有5年以上node开发经验才能玩的转的,因为express是非常的精简的,安装它后,会发现它几乎不会为你提供任何编码规范,也没有约束你的框架应该怎么设计,以至于新手下载完成后完全不知道自己应该干嘛,甚至不知道直接的文件应该写在哪,没有框架本身的约定,标准的MVC模型有着千奇百怪的写法,所以我觉得没有一定的架构思想和经验是很难驾驭的。
koa我并没有直接的使用过,只是听说是express的原班人马打造的,中间件是基于洋葱圈模型实现的。下面上一张图洋葱圈模型图。
而是后来直接就接触的egg,egg标语是“为企业级框架和应用而生”,通道
废话说的有点多了,重点是通一套前端代码,开发了两套后端代码,功能是完全一致的,后端都实现了相应的jwt验证功能,-->json web token,密钥都是我们约定好的固定值,但是最后发现一样的密钥,相同的数据,使用的jwt包不同产生的结果也不同,这也就导致两端之间无法相互切换,每次切换必须从登陆重新开始,这不太符合逻辑,而且重要的是后面的安排有需要这样的功能,无法做到无缝切换就直接导致实现不了下面的功能。
提纲内容
- jwt实现原理
- jwt未能解决的疑惑
- base64和base64url
jwt实现原理
其实作为一个前端开发人员,jwt实现原理我是没必要懂得的,但是如果你不限于此,这算是个必不可少的内容了吧。
先上一张图。
图中数字1是后端使用jwt工具包生成的token,通常是由三部分组成,也就是token中间的两个“.”将其分为三部分,第一部分对应的是右边的数字2部分,然后依次对应。
这三部分分别是头部、有效载荷、签名。
头部:alg是指说用到的算法,type当然是令牌类型
有效荷载:sub所签发的用户,name是签发者的姓名,lat是这签发时间,exp是指到期时间,当然还有一些其他的,这些数据都是非必要数据,实则只有exp可能有用,因为有效数据实际都是在data里面,当然你也可以不这么做。
签名:前两者都是通过base64url编码过的,而非是算法加密的,所以几乎是透明的。但是签名是默认是通过hsa256算法加密的 ,加密的规则是:
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
your-256-bit-secret
)
如何验证token呢?那更加简单了,就是用前端传回来的token前两部分和服务器存的秘钥再次加密一次,然后做base64url处理和第三部分比较,一样代表这个token是自己签发的,不一样代表是伪造的,完了过后再将有效载荷部分进行base64url反编码,就得到exp,然后和当前时间比较是否过期。
jwt未能解决的疑惑
经过测试,发现三个问题。
1、 node和java使用对应的jwt工具包生成的token不相同,这里是指在一系列参数完全相同的情况下。
2、 还发现用java生成的token在jwt官网解析时候输入秘钥结果的到的签名和自己的签名不一样,但是node是一样的,于是就产生了java工具包在输入签名的时候对密钥进行了其他处理的想法,但是他并没有找出做出来怎么样的处理,也就是说我们在生成签名的时候根本就连密钥都是不一样的。
3、 不管是node还是java生成的token,我们用原来一模一样的数据和一样的算法公式都产生不了和工具包生成一样的签名,也就是可以怀疑在进行hsa256算法加密前确实对秘钥进行处理了。
base64和base64url
base64就是一种二进制编码方式,原理很简单,先准备一个包含64个字符的数组:
['A','B','C',...'a','b','c',...'0','1','2',...'+','/']
然后对二进制数据进行处理,每三个字节一组,一共24bit,一个字节8bit嘛,然后再将24分为4组,每组正好6bit。6bit的话就刚好能表示64个字符。如果编码字符不是3的倍数,就会剩下一个字节或者两个字节,这个时候就在后面填充\x00,再在编码末尾加上一个或者两个=号。解码的时候制动力去掉就好了。
base64url编码就是将字符编码成url能传递的参数,因为base64编码会出现+号和/号,然后就会在url中出现问题,所以base64url其实就是将+和/分别变成-和_
手写jwt验证,实现java和node无缝切换的更多相关文章
- 算法是什么(二)手写个链表(java)
算法是什么(二)手写个链表(java) liuyuhang原创,未经允许禁止转载 目录 算法是什么(〇) 很多语言的API中都提供了链表实现,或者扩展库中实现了链表. 但是更多的情况下,Map(或 ...
- 手写代码注意点--java.lang.Math 相关
1-如果用到了Math的函数,需要手动写上: import java.lang.Math; 2-求x的y次方,用的是Math.pow(x,y); 注意,返回值是double!!! 不是int, 如果需 ...
- 手写代码注意点--java.util.Stack相关
1-Stack的基本函数为: 注意: 取栈顶的函数为peek(),不是top()... 测试stack是否为空的函数为empty(),不是isEmpty()...
- java 从零开始手写 RPC (07)-timeout 超时处理
<过时不候> 最漫长的莫过于等待 我们不可能永远等一个人 就像请求 永远等待响应 超时处理 java 从零开始手写 RPC (01) 基于 socket 实现 java 从零开始手写 RP ...
- 2 手写Java LinkedList核心源码
上一章我们手写了ArrayList的核心源码,ArrayList底层是用了一个数组来保存数据,数组保存数据的优点就是查找效率高,但是删除效率特别低,最坏的情况下需要移动所有的元素.在查找需求比较重要的 ...
- 阿里第二轮面试:手写Java二叉树
阿里面试 现在很多公司在招聘开发岗位的时候,都会事先在招聘信息中注明面试者应当具备的知识技能,而且在面试的过程中,有部分对于技能掌握程度有严格要求的公司还会要求面试者手写代码,这个环节很考验面试者的基 ...
- 教你如何使用Java手写一个基于链表的队列
在上一篇博客[教你如何使用Java手写一个基于数组的队列]中已经介绍了队列,以及Java语言中对队列的实现,对队列不是很了解的可以我上一篇文章.那么,现在就直接进入主题吧. 这篇博客主要讲解的是如何使 ...
- 6 手写Java LinkedHashMap 核心源码
概述 LinkedHashMap是Java中常用的数据结构之一,安卓中的LruCache缓存,底层使用的就是LinkedHashMap,LRU(Least Recently Used)算法,即最近最少 ...
- 使用java语言基于SMTP协议手写邮件客户端
使用java语言基于SMTP协议手写邮件客户端 1. 说明 电子邮件是互联网上常见的应用,他是互联网早期的产品,直至今日依然受到广大用户的喜爱(在中国可能因为文化背景不同,电子邮件只在办公的时候常用) ...
随机推荐
- redis等缓存
文章出处 https://www.cnblogs.com/wupeiqi/articles/5246483.html Model 到目前为止,当我们的程序涉及到数据库相关操作时,我们一般都会这么搞: ...
- Web开发小贴士 -- 全面了解Cookie
一.Cookie的出现 浏览器和服务器之间的通信少不了HTTP协议,但是因为HTTP协议是无状态的,所以服务器并不知道上一次浏览器做了什么样的操作,这样严重阻碍了交互式Web应用程序的实现. 针对上述 ...
- 尹吉峰:使用 OpenResty 搭建高性能 Web 应用
2019 年 8 月 31 日,OpenResty 社区联合又拍云,举办 OpenResty × Open Talk 全国巡回沙龙·成都站,原贝壳找房基础架构部工程师尹吉峰在活动上做了<使用 O ...
- 超级好用的c#解析JSON
分享c# 一款非常好用的操作Json的dll,litjson VS2017 NuGet 搜索litjson,如下图: 例子: 在项目中新建一个txt文本文件,内容如下: [ { , "use ...
- Ubuntu 16.04安装Java 8
1 Java 8 下载地址 http://www.oracle.com/technetwork/cn/java/javase/downloads/jdk8-downloads-2133151-zhs. ...
- java命令行导出、导入sql文件
@IocBean public class SqlCommandModel{ //用户名 @Inject("java:$conf.get('jdbc.username')") pr ...
- 【Spring Cloud】客户端负载均衡组件——Ribbon(三)
一.负载均衡 负载均衡技术是提高系统可用性.缓解网络压力和处理能力扩容的重要手段之一. 负载均衡可以分为服务器负载均衡和客户端负载均衡,服务器负载均衡由服务器实现,客户端只需正常访问:客户端负载均衡技 ...
- Windows 批量修改文件后缀名
利用ren 文件名替换命令 for循环去批处理 @echo off for %%m in (*) do ( if not "%%m"=="temp.bat"( ...
- 3.1 C语言_实现AVL平衡二叉树
[序] 上节我们实现了数据结构中最简单的Vector,那么来到第三章,我们需要实现一个Set set的特点是 内部有序且有唯一元素值:同时各种操作的期望操作时间复杂度在O(n·logn): 那么标准的 ...
- 14.Nginx四层负载均衡
1.七层负载均衡: 根据url 调度不同的集群 url.cheng.com 10.0.0.5 10.0.0.7 /pass 10.0.0.8 /user 1.web01和web02配置 (只不过代码不 ...