00:00
呃,好,我们接下来的话呢,我们已经由于我们之前呢,已经把这个呃权限管理模块的并类呢,都已经写完了,那么接下来的话呢,我们写一些工具类,或者叫做工具函数呃帮助我们辅助我们做一些事情,所以说在这儿的话呢,首先我新建一个软件包呢,叫做呃的命点U对吧?那么我要新建的第一个工具类叫做什么呢?叫做MD5啊,那么我们在这里边的话呢,我们就要明白说是这个MD5这个工具类,它主要是用来干嘛的,对吧?也就是实际上就是MD5呢,它是一种加密算法,呃,那么MD5这种加密算法的话呢,它用来干嘛呢?在我们这个项目里面对吧?用来将铭文密码字符串加密为密文密码字符串,对吧?实际上他就是做这个事情的。
01:00
呃,为什么呢?因为我们在数据库里边,你不可能直接把用户的呃铭文密码字符串呢,直接存下来,对吧?呃,你如果直接把用户的这个铭文密码字符串存到数据库里边,对吧?那么这样的话呢,就有这种脱库的风险对吧?呃就是说呃实际上之前呢,也出过很多类似的事故,呃就是一家网站的,呃这个用户数据库呢,被。黑客呃,进行了脱裤对吧,进行了脱裤操作,那么就是这个呃呃这样的一个操作啊,那么脱,呃,那么把这个库拉下来以后呢,发现。里边的密码呢,都是铭文密码啊,当然还有用户名啊,那这样的话呢,实际上用户数据就彻底泄露了,我就可以拿这个用户名和密码呢来进行登录,所以说我们在把密码存入数据库之前呢,必须把它加密为密文密码字符串对吧?呃,当然就是说这个MD5算法呢,你本身不需要说是特别关注它对吧?本身不需要呃,特别关注它是干嘛?呃,实际上嗯,它主要是一些数学公式的转换,呃当然就是说你也可以不用MD5加密算法对吧,也可以使用一些其他的加密算法,比如说像呃这个me me哈西SHAHA256对吧?呃,包括SHA512。
02:31
等等等等,那这些你都可以使用,那这里边的话呢,我们就呃使用一个MD5来说明问题就可以了啊,因为这个算法呢,主要是涉及到一些加密算法的一些底层原理,所以说我们就不详细讲解了,呃,直接把它对吧贴过来,我就直接把仓库里面的代码给它贴过来,好我们把这个encrypt,呃,这个方法对吧。给它贴过来,这个精态方法呢,给它复制过来好,那么在这里边的话呢,你要注意。
03:05
STRC,这个是原字符串,这个是原字符串,那这个呢,是16进制。对吧的字符的16个字符对吧,0123456789,然后ABCDEF这个我相信大家都比较熟悉了,呃,然后下面的这个呢,是什么呢?原字符串的字节数组对吧?然后呢,在下面的话呢,我们获取MD5的加密实例对吧?呃,实际上就是它的加密类的一个实例化。然后呢,我们用这个BAS,也就是用这个原字符串的字节数组呢,更新一下这个实呃,MD5加密实例,然后呢,调用dIgEst的方法呢呃,赋值到BYS上面对吧?呃,然后在这的话呢,我们遍历这个字节数组,然后每立一个字节呢,遍历字节数组,然后将每一个字节对吧?将字节数组里面的每一个字节呢都给它转成一个16进制字符,将字节数组中的每一个字节都转换成一个16进制的字符,对吧?然后呢,将字节数组转成字符串返回对吧?将字节数组转成字符串。
04:49
返回,而这个字符串呢,实际上就是密文字符串,我们现在我们来看一下它的这个加密效果啊呃,我在这里边的话呢,我写一个main函数,呃,然后呢,当然比方说我们的铭文密码是多少呢?比如说在这里边password对吧,铭文密码是六个一。
05:08
好,然后呢,我们把它的密文字符串呢,给它打出来对吧,MD5点encrypt password。OK,我们现在我们来执行一下这个main函数,来看一下,呃,字符串六个一,它转成的呃密文字符是什么?那你可以看到诶,它加密以后呢,实际上就是什么什么96179这样的一个随机字符串,对吧?也就是说我们最终要在数据库里边保存的呢,是密文字符串。对吧,在数据库中保存的是密文字符串,好啊,那现在的话呢,我们这个MD5的这样的一个,呃,就是说加密算法,或者说加密算法的这样一个工具类呢,我们就已经写完了,OK,呃,那么我们要写的第二个是什么呢?呃,我们要写的第二个呢,就是有关JWT的对吧,有关JWT或者说Json web token的这样的一个,呃,就是说工具类,对吧,JWT,呃,Helper,我们就起一个j wt helper这样的一个名字吧。
06:24
好啊,那我们首先我们要知道说这个JWT,它实际上是Jason web token的缩写,对吧?JWT呢,它实际上就是Jason web token的这样的一个缩写啊,那之前我已经大概的说过,就是说我们的这个Json web token呢,呃,它主要是用来干嘛的呢?实际上就是用户登录时。对吧。当然用户你登录的话呢,你会向我们的后端发请求,那么后端会根据用户信息来生成一个JWT令牌对吧,这次web token对吧?这个呃,Token实际上就是令牌的意思啊,后端呢,会根据用户信息呢,生成一个呃JW令牌,令牌并返回给前端,那么前端的后续请求啊,那么前端的后续请求呢,就可以带着。
07:40
啊,这个JWT呃令牌来访问对吧,那么后那么前端的后续请求呢,就可以带着JWT令牌呢啊来向后端发送请求对吧?当然就是说由于我们这个前端它后面的请求呢,已经带着这个JWT令牌呃来向后端发送请求了,那么这个的好处是什么,是什么呢?
08:13
无需重复登录啊,那么我们的这个工具类呢,实际上就是根据用户的信息呢,来给它呃创建一个呃,JWT令牌,当然这个JWT令牌它实际上也是一个类似于加密过的这样的一个字符串,对吧?好,我们现在的话呢,Public static,呃,Long token。XP。Grion等于什么呢?等于365L乘上24乘上60,再乘上60,然后再乘以1000,也就是说这个呢,是令牌的过期时间对吧?呃,因为我们之前我们都知道说我们的这个GWT令牌啊,它返回给前端对吧?那么前端会将JWT令牌保存在什么呢?浏览器的cookies里边对吧?那么这样的话呢,我前端的后续请求呢,你就可以从cookie里边把这个JW硬牌呢取出来对吧?然后带着这个令牌呢,向后端发请求,这样就无需重复登录了,当然由于我们浏览器的cookci呢,它实际上是个过期时间的,所以说我们这里边我们先声明一。
09:44
一个全聚变量啊,或者说常量token,呃,Expration对吧,就是它的过期时间,当然我这里面过期时间呢,我设置为呃一年对吧,当然一般来说不会设置这么长,可能就是呃一周或者两周的时间啊呃,那么第二个的话呢,我们需要有一个K对吧,加密的key,我是需要一个这样的一个东西的,那么这个加密的key的话呢,就是private static。
10:12
Key等于什么呢?等于K点。对吧,H ma Sha for对吧?我调用这样的一个方法,当然你不需要管他说,呃,这个方法具体是要干什么对吧?你只需要知道它是一个T就可以了,因为它也呃实际上涉及到了很深的呃这样的呃加密学或者说密码学的一些原理,对吧啊。啊,然后在这的话呢,我就随便呃它的T的话呢,我是由什么生成呢?我是由一个字节数组生成的,呃,当然这个字节数组的话,我就随便呃产生一个对吧,比方说ABCDEFGHIJKLMNOPQRST,对吧,UVWXYZ对吧?啊,当然当然你光产生这26个字母可能还不太够,所以说可能后面我们还会需要一些,呃,比方说什么asdf呀,什么随便的你就可以,呃呃,都可以来用,对吧,只要是字母就可以,然后呢,点get bys,那这个就是字符数组,好,字节数组,OK,我们现在加密的key的这个常量呢,我们也已经写好了,呃,那接下来的话呢,我们要写什么呢?我们要写就是说生成token的方法对吧?那么生成token的方法呢,那就是private state string啊,所以说你认为你可以看到说这个令牌,其实它也是一。
11:40
一个string类型,或者说字符串类型的这样的一个东西,对吧,Create token,我们根据什么来生成呢?根据。用户ID,还有呢,就是用户名对吧?我们根据用户ID和用户名呢,来生成一个token对吧?来生成一个token啊呃,那么在这的话呢,我们怎么生成呢?那我们就直接调用方法我们都知道,呃,之前实际上我们在POM文件里边,我们实际上是导入了一个叫做JJWT这样的API,对吧?呃,或者是这样的一个库,所以说我们直接使用JJWT这个库呢,来给我们生成,呃,就是说ton啊,那么在这的话呢,我们就是JWTS对吧,然后点builder。
12:31
然后呢,点set subject,那么在这里边的话呢,我们是一个p two p-U对吧,你其实不不需要管它是这个到底是干嘛的,好,然后点set expiration对吧,那这个就是,呃,其实就是我们的过期时间,那么这个过期时间是什么时候呢?当然我要new一个date。对吧,然后呢,system.current time minutes,也就是当前的系统时间,加上我们之前设置的呃,这个长量对吧,加上我们设置的这个过期时间,那就是它最终的过期时间,就是我们现在的时间,加上这个过期时间的长度一年对吧,就是一年以后的,现在呢,啊,就是这个token的过期时间,然后呢,我们要根据什么呢?我们要根据U的ID,也就是根据用户ID呢,以及对吧,以及用户名。
13:35
呃,来生成token,我这里面只是使用了用户ID和用户名来生成token,当然你也可以比方说。呃,把其他的信息也给加进去对吧?比如说呃,像用户昵称呀等等等等都可以加进去,我这里面为了简单的话呢,我就只根据对吧,根据用户ID和用户名生成令牌对吧?我只根据这两个信息来生成令牌,好啊,然后接下来的话呢,我们就点sign with key对吧,我们生成令牌,然后呢,点compact,也就是呃,我这里面的话呢,对它进行一个压缩,那这样的话呢,就生成令牌了啊。
14:20
OK啊,那我们现在有了一个生成令牌的方法以后呢,呃,我在这里边的话呢,我就可以使用一个main函数来进行测试一下,对吧?呃,也就是在这的话,比如说string token等于什么呢?J wt helper.create token。对吧,比如比如说我的用户ID呢,是EL,我的名字呢,比如说是啊的命对吧,或者叫做左源都可以,然后呢,我们把这个token大家打出来看一下,用户ID是一用户名是的in的,呃,根据这样的信息对吧,也就是这样的用户信息,我们生成的token是什么。
15:03
OK,那你可以看到它生成token,就是一长串这样的一个字符了,对吧?呃,这样的一个我们看不懂的随机字符串啊,当然你除了有生成token的呃,这样的一个,呃,就是说呃方法呢,我们还需要从token里边呢,获取用户名和密码对吧?也就是在这里边呢,我们还需要两个工具方法,根据用户名,根据token对吧,提取用户名对吧,或者说用户ID,那这是一个方法,当然我们还需要另一个方法呢,就是根据token提取用户名对吧?也就是说它前为什么我们要有这样的方法呢?呃,那就是说我们前端他带着token过来以后,你总要知道这个token是谁的token吧,所以说我们必须要可以根据这个token呢。
16:04
呃,把用户ID可以提取出来,或者说根据这个token呢,把用户名给它提取出来好。我们现在我们来编写这样的方法,Public c law get user ID对吧,那这个就是。提取用户ID的方法,呃,当然他接收的参数呢,就是token了,我们要呃,根据token呢,把它的用户ID呢给它取出来,好,然后在这的话呢,我需要补货异常catch exception e,然后呢,当然我们可以把这个异常的调用站给他打出来,然后呢,同时返回一个那。啊,然后在这里边的话呢,我们首先判一下空对吧,如果token它是一个na的话呢,我们直接returnna对吧,当然一般来讲的话呢,他头恨不是那好。呃,那么第二个的话呢,就是说我们要做一个什么样的事情呢,首先在这里面的话呢,我们直接一个腕对吧?呃。
17:08
Claims g ws啊,那么它等于什么呢?等于GWTS.pass build点。Set set key对吧,我们之前已经有key了,我们要根据这个key呢来呃把它呃解析出来,把这个用户用户ID给它解析出来,然后再build,然后呢,Pass claims,呃,GGWS,然后呢,Token,好。呃,那这个是我们的第一个要用的方法,那在这里边的话呢,你要注意的话呢,就是我这里面的有一个va关键字对吧?呃,那么这个是扎va,扎VA11之后,呃它进呃他引进了一个关键字,那么这个va关键字呢?呃,它的作用是什么呢?就是说局部变量可以不写类型声明对吧?也就是说Java可以自动推导推断我们这个局部变量的类型,呃,实际上就是说我这个袜呢,其实它就是节省我们编写类型声明的这样的一个工作量的一个语法糖,对吧?嗯,那这个的话呢,实际上就是我们局部变量呢,你不需要去写类型声明,呃,Java呢,可以自动推断局部变量的类型,呃,其实就是说,呃类型推断这样的一个功能呢,其实在。
18:41
我们的现代的编程语言里面,对吧?呃,呃,实际上它都是很常见的,那么Java呢,也就加了进来,比方说这个呃,像GALA对吧,比方说像呃,这个rust,呃,Gola type script等等等等都具有呃类型推断功能,对吧?所以说Java它也是必须得加进来,要不然他就落伍了对吧?呃,包括像呃,像什么costing啊等等等等,其实都是有的哈,然后va claims等于什么呢?
19:22
等于claim j ws.get包点好,然后接下来的话呢,我们就是y user ID等于claims.get。UID对吧,那这个的话呢,然后点two。对吧,也就是这一步,实际上就把它的呃,这个用户ID呢,呃给它提取出来了,对吧,给它提取出来了。好,呃,当然在这的话呢,我们可以比方说你可以写一个string对吧?呃,然后呢,把这个get ID的这个ID呢给它去掉对吧?呃,当然这个string的话呢,其实你也是可以写成word,它可以自动推导出来,呃,也就是说经过上面这三步呢,我们就把user ID呢给它,呃就是说提取出来了,然后提取出来以后呢,由于我们的user ID呢,它本身是一个浪类型的,所以说在这的话我们浪点pass浪一下OK啊,那在这的话呢,我们就编写好了根据token提取用户ID的这样的一个功能,对吧?呃,你比如说在这下下面我们可以打印一下,那就是g wt help.get u的ID token对吧,我们来看一下它能不能把用户ID这个一呢?呃给正确的提取出来,对吧?
20:53
啊,那在这的话呢,我们就可以看到,诶,它已经正确的提取了,好呃,我们现在已经编写了根据token提取用户ID的呃,这样的一个方法,那么接下来的话呢,我们再编写一个根据用户名对吧?呃,或者说根据这个token提取用户名的这样的一种方法,当然他接收的参数呢,也是投Ken,好呃,当然我在这里边我还是需要做一个捕获异常exception,然后呢1.printsta,然后呢,Return now,好。
21:32
呃,当然上面的话呢,我们就一样画葫芦,它写写法都是一样的,如果token等于now,那么我们直接return now对吧,然后呢,Claim g ws对吧?它等于什么呢?等于。呃,GWTS.passer build.set s key,也就是说我们要用上面的这个key呢,对吧,根据这个key呢,来把用户名给它提取出来,因为我们token呢,就是根据这个key以及用户ID和用户名呢来生成的,好,然后呢,Build,然后点pass,呃,Claims g ws,然后呢传入token啊然后呢,就是claims等于什么呢?
22:24
呃,等于claim j ws.get body对吧?然后呢,呃,接下来的话呢,我们就是return一个。s.gET对吧,Username to three好,那这样就啊没有问题了,对吧?啊,这样就没有问题了,OK,当然我们还是本着保险的原则,还是要对它进行一个测试对吧?我们看通过这个token,他能不能把admin这个。
23:01
用户名呢,给他正确的提取出来。OK,那你可以看到,诶这个用户名呢,我们已经正确的提取出来了啊,那这样的话呢,我们的这个j wt helper呢,就编写完了啊,那我们接下来我们要编写的是什么呢?接下来我们要编写的是有关权限的一个呃工具类对吧?那么它的名字叫做什么呢?叫做permission helper对吧?那么这个permission helper它的作用是什么呢?呃,首先我们要理解的就是呃,我们之前对吧。我们有讲过说这个权限呢,呃,实际上它是一个树形结构对吧,也就是说有一个某一个权限,它有可能有上级权限对吧,或者说叫做负权限啊,所以说呢,呃,而每一个权限呢,它实际上对应了一个呃菜单的访问权限对吧?它其实每一个权限都对应了一个菜单的访问权限,所以说我们现在需要做的是什么呢?我们现在需要做的是根据权限数据呢,可以可以构建出构建菜单数据对吧?那我们这里面我们都知道,呃,实际上权限数据或者说权限表里面,它存的权限数据呢,是一个呃,就是说树形结构,那对于树形结构来讲的话呢。
24:36
我们想要便利一个树形结构的方法,实际上就是使用递归的方法来来做这件事情,对吧?使用递归的方法来做这件事情好。也就是说我们在这里面的话呢,我们要使用递归方法来构建菜单,对吧,当然在这的话呢。
25:02
呃,我构建出来的这个菜单数据对吧?它的返回值呢,是一个a list,也就是说是一个列表,那么这个列表里边呢?呃,它的类型呢,是permission这样的一个Java病的这样的一个类,对吧?我们之前写过的好,然后build,那么它根据什么来进行构建呢?呃,它根据的也是一个权限的列表,对吧?当然这个权限列表里边的每一个数据。对吧,它实际上都是树形结构里边的一个节点,所以说我们给它起的变量名呢,叫做吹no,叫做吹no OK,那么在这的话呢,Va trees,首先我们new有一个a list,这个a release里边的呃变量类型a release源的类型呢,是permission这样的一个呃权限的扎va病类,对吧?然后呢,我们便利吹not中的所有节点对吧,实际上就是树形结构里面的所有节点,然后呢,For循环,我们这边直接使用Y,对吧,因为扎va有对局部变量的类型推断能力,吹node,然后吹no,我们遍利每一个吹node,那么如果节点。
26:28
对吧的什么呢,上级权限的ID。对吧,是零。那这说明什么呢?如果一个节点的上级权限的ID是零,那实际上说明它是一个什么呢?它是一个全部权限,对吧?因为我们都知道,之前我们往权限表里边插入数据的时候呢,你会发现我们的第二个字段parent ID呢,实际上就是它的上级权限,你会发现只有全部权限。
27:04
只有all这个权限呢,它的上级权限的ID是零对吧?所以说在这里面的话呢,我们要判断一下,那说明是全部权限对吧?说明这个东西,那么它在树形结构里边的层级是什么呢?对吧?当然我们在这么if tree no的点呃,Get对吧,Parent ID等于零,那这说明什么呢?对吧?说明它在树里边的层级结构是第一层对吧,它是位于第一层的,所以说我们在这的话呢,吹no点呃,Set level1对吧,所属。数形结。
28:00
所属层级对吧,是一好啊,当然除了这个以外的话呢,我们还需要做的一个事情就是呃。Trees,这个是我们的反位值trees.add。对吧,然后呢,我们调用一个什么方法呢?调用一个find children吹notde,吹not啊,当然我们这个find children这个方法我们还没有编写啊,我们还没有编写,然后呢,我们在这的话呢,我们返回什么呢?我们返回trees,好,那么这个find children它主要用来干嘛呢?它实际上就是在吹nos树形结构中寻找node的所有子节点。
29:03
对吧,所以说实际上我们这个Bill的方法呢,其实就是根据数据库里面保存的这个吹no列表,对吧,构建出一个树形结构来,好,接下来我们就把这个find child的这个方法呢,给它实现一下,对吧?那这个方法的作用就是递归查找子节点,OK,那么它的方法名对吧?当然它查找出来的结果呢,是一个permission,对吧,Find children OK permission tree node。这个是树形结构里面的某一个节点,然后呢,List permission吹no对吧?啊,当然这个就是树形结构里面的所有节点,我在树形结构里面的所有节点里边呢,去查找某一个节点的子节点对吧?查找某一个节点子节点,好我们当然我们第一步呢,首先吹node set children,也就是在这里边呢,我首先给他对吧。
30:14
将吹node的子节点设置为空列表,对吧?设置空列表以后呢,然后接下来的话呢,我们递归的去寻找它的子节点,然后把它的子节点插入到这个列表里面就可以了,对吧?递归的寻找tree node的子节点,然后将子节点插入到列表中对吧?插入到列表中好,我们怎么来实现呢?首先for循环Y,我的这个局部变量呢,叫做eat,然后呢,吹no子对吧?我们要在这个树形结构里面的所有节点里面去寻找它,对吧?然后呢,如果。
31:13
如果我们这个吹node它的。呃,这个ID呢,对吧,等于这个局部变量的。负权限ID对吧?也就是说如果我们的这个数音,如果我们这个吹node的呃权限ID对吧,等于这个局部变量的负权限ID,那这是说明什么呢?说明it这个局部变量,它就是我们吹no的子节点对吧?所以说在这的话,我们判断一下相等如果objects对吧。第二,Eagles。吹not.get ID,然后呢,eat.get parent ID好,然后接下来的话呢。
32:06
it.set level对吧?当然它的这个level呢,肯定是train no的level加上一对吧,也就是在这里边我们要写一下注释,如果it权限对吧的负上级ID,上级权限ID等于吹node的权限ID说明什么呢?说明it权限是train no的权限的子权限对吧?那你既然eat权限是吹note权限的子权限的话,那我eat的所属层级自然。对吧,需要在吹node的层级上加一了,那这是没有任何问题的啊,那么如果吹node.get吹不准。
33:12
等于now对吧,就是他没有子孩子,或者说没有子节点,那么我们需要set children,呃,你有一个release,呃,当然这一步你不做也可以,因为我们在这的话,我们已经给它创建了一个空列表了啊,然后接下来的话呢,我们吹no的点get children对吧,那么获取它列表,然后at对吧,然后把它子节点都给它添加进去,然后在这里面的话呢,我们就是find children eat tree nots。好OK,然后呢,我们在这,我们return node就可以了。对吧,Return就可以了。OK,呃,那这样的话呢,我们的权限列表呢,也就给它,呃,做成了一个数据结构对吧,做成一个树形结构,好,那现在的话呢,我们啊的命模块的,呃,这个类呢,我们就都已经写完了,啊的命模块的工具类呢,我们就都已写完了,那接下来的话呢,我们就开始编写针对数据库的增删查改服务。
我来说两句