【快到最后了~~
撒花花庆祝一下~~cheers~】
7.1 Spring Security

接下来式提高系统的安全性和性能
面试找工作的重点
servletAPI就是javaEE

--- spring security的底层是靠什么来保证用户的权限的。会基本的使用之后在看技术文档和源码。
在springmvc中,所有的请求都发给了dispatcherServlet,然后它再将所有的请求都发给了各种控制器。

controller和intercepter是springmvc的特有内容,但是dispatcherServlet不是springmvc专属的内容,它满足javaEE的规范。它是一个servlet的实现类。
Filter也是满足avaEE的规范。
Filter可以拦截对于Servlet的访问。
Intercepter可以拦截对于Controller的访问。
Filter和springmvc没有什么关系,filter是javaEE的标准。


spring底层要利用统一的机制处理所有的权限。它是利用javaEE的规范,也就是Filter组件。有11个Filter每一个Filter负责专门的一块内容。认证,退出,权限保存等~~
也可以自定义Filter。
-- 老师给推荐的网站,学spring security

跟踪一下核心的模块。
---- 实例演示
实践的基础代码:springsecuritydemo

这里还没实现,使用security来接管实现。
目前存在的权限问题:所有的权限都没有进行处理,任何一个人都能访问所有的页面以及管理员页面。
-
导包
图片.png
去掉版本,使用父pom中的版本。
账号:user

只要引入这个包,权限控制立刻生效。
STEP 1:


STEP 2:


不一定是非得在userService这个类上扩展方法,只是这个类中已经有了该有的方法,因此使用这个方法更加方便。


providerManager并不是自己进行认证,它内部包含了一组组件,组件进行认证。
因为我们不只是可以通过账号密码进行登录,还能通过微信或者是qq进行登录。使用指纹或者脸也可以登录,ProviderManager兼容了所有的登录模式。每一个组件负责其中一种认证。这在设计模式上叫做委托模式:
认证信息是指账号密码。

哎,恶心死了呢,好麻烦


参数解释:


------- 以上是认证的逻辑,接下来讲授权的逻辑
通过授权的逻辑,我们发现程序上来之后就执行父类的逻辑,如下所示:

这些代码说明了,所有的请求都会进行认证,假如我们不想进行这样的认证,将下面的红色部分取消:

这样的话,我们不需要走springSecurity的登陆页面,而是可以配置自己的登录页面。需要说明
- 登陆页面
- 登陆表单
- 登录的请求
按照如下固定的配置方法:

1是重定向,2是转发。

知识点补充:
转发和重定向:
两个独立组件之间的跳转适合使用重定向
如下图,a和B是服务器的俩个组件。
重定向:

在这种情况下,a不太方便给b携带什么数据。只能使用cookie或者session携带数据。
关于转发:
a只能处理一半请求,另一半需要由b进行处理,这种情况下使用request,request请求没有进行重置,这是同一个请求。a在转发的时候需要将request和response给B。

转发情况下,浏览器并不知道有B的存在,因此浏览器的地址栏一直显示的都是A的地址。
但是在我们的这个例子中,不是在controller中,没有模板可以进行重定向,只能进行转发。
-
退出配置:
图片.png
-
授权配置:
拥有哪个权限能够访问哪个路径。表示权限和路径的对应关系。
页面设置:
图片.png
1表示只有user或者admin才能访问letter
2表示只有admin才能访问管理页面
3表示但凡是不匹配的页面都会访问/denied页面。
图片.png
-
配置提交表单的路径
得有名字才能被authentation拦截到
图片.png
security有一个要求,在退出的时候必须使用post请求。


管理的结果:

关于验证码不能在下面的地方进行验证,下面的红色部分只是账号和密码:

-
如何验证验证码:
在账号密码验证之前增加一个Filter,进行验证。
只对登录请求进行验证
图片.png

a表示让请求继续向下走,走到下一个Filter,如果没有了Filter,就向下到servlet。因为有多个Filter,因此加上这么一句。
-
记住我
图片.png
页面稍作更改:

测试一次不点记住我的反应。
7.3 权限控制

本节目标:将之前的security运用到我们的项目中
- 导包
-
2 . 废弃之前的登录请求拦截器
图片.png
-
在常量接口中增加几个常量,声明一下系统的各种权限,以及用户的身份种类。
图片.png
-
在config包下新增一个security的配置类
重写这个方法里面的三个configuration方法。
在webSecurity中是忽略掉对静态资源的拦截。
因为我们的代码里面已经有了关于登录 和退出的相关功能了,因此,我们不再写登录和退出,之后会说如何绕出security中的登录和退出方法。
然后是授权,在授权的时候,我们审阅所有的controller里面的路径,记录下哪些是需要登陆了才能够访问的。
图片.png

-
权限不够的处理
上一节课我们使用的是accessDeniedPage,但是本节课使用这个就会显得比较简陋。
因为我们的请求有各种形式,普通的请求希望返回的是页面,异步请求希望返回的是json字符串,因此不能使用统一的返回页面的请求。
没有登陆时的处理:需要进行认证
图片.png
accessDeniedHandler:表示登陆了但是权限不符合时的处理。
这两个接口里面的方法都是表示当发生不符合状况时应该采取的办法。里面分别写了针对同步请求以及异步请求的处理办法。
这个异常表示没有登陆时进行的错误提示。

判断是不是异步请求:

声明返回的时普通字符串,同时声明字符集好让它支持中文。

假如没有权限被服务器拒绝,而不是因为服务器报错, 使用状态码是403。

-
没有登录时的异步请求:
图片.png
权限不足但是已经登陆了,因此重定向到denied的页面:

将下面的拷贝到homeController中:

security会拦截我们的logout请求,在controlller之前进行处理,因此我们自己写的推出代码没法执行
返回一个跟推出有关的页面,对其进行配置。
下面画横线的路径根本就不存在,我们想让程序拦截这个路径,善意的欺骗哈哈哈哈,ctrl进去可以发现原本security想拦截的路径是/logout。

我们不再使用security进行认证,而是使用我们自己写的逻辑进行认证。但是需要将最后的结果存储在 token中,这样在授权的时候才能从cesuritycontext中取出token然后进行验证。这一次我们不用将user以及userService再扩展某个接口了。
-
根据用户获得用户的权限
图片.png
-
-
在什么时候获得用户的权限并且将用户的权限token存在context中。
图片.png

-
在退出功能中也应该将权限清理一下
图片.png
CSRF攻击的基本原理,以及security使用什么方式进行预防

某网站盗取你的登陆凭证,模仿你的身份去访问另一个网站,向另一个网站去提交数据。这种攻击都是发生在提交表单的时候。
解决办法:他会在返回的表单中生成一个隐藏的token ,这个token 每次都是变化的。其他网站可以获取cookie但是没法获取token,以此防止被攻击。

-
运行程序,展示这个token
图片.png
但如果是异步请求就没有办法进行处理,我们必须得自己进行处理。
异步请求的话没有表单,security会在这生成对应的数值。有了security之后,每次发送消息都会生成-csrf,我们可利用它来获得需要的内容。
通过请求的消息头进行传递,消息头里面是key:value对应。

如下所示,对异步请求的请求头进行设置:



-
接下来,给所有的异步请求都得加上以上的防攻方法。
-
在security config中禁用掉csrf即可,如果不想禁用可以课下自己操作。
图片.png
-
我们可以测试访问哪些没有登陆不能访问的页面,会发现不能访问。
7.5 置顶,加精,删除功能

-
导包,找到支持授权的tymeleaf。
图片.png
删除版本:
图片.png
-
数据层
图片.png

-
业务层
图片.png
图片.png
-
controlller
那个???redis等其他的那些不用改变了吗??
置顶.png

添加一个删帖的主题:(怎么记得它对status=2有判断?难道是我记错了??)



-
处理页面(discuss-detail.html)
图片.png
接下来在js文件中,给这三个按钮添加事件,发送异步请求。
${function()}表示在页面加载完之后执行里面的函数,开始给按钮增加方法。

-
开始写这三个方法:
置顶.png
加精.png
删除之后是跳转到了首页,这是又发出了一次请求????
图片.png
- 测试,对某一个帖子进行置顶加精和删除,然后对比数据库中type和status的变化。发现不错。
-
目前的问题
点击置顶之后他呈现的状态是正确的,是灰的,但是再次刷新之后又变红了。我们需要根据真实状态进行状态的呈现。
删除这个没必要这样吧,删除之后压根就不会呈现出来的吧。
图片.png
-
接下来开始处理权限问题:
图片.png
-
再次测试
分别使用普通用户,管理员和版主 -
有一个问题---关于页面的
既然不能点,也跟就别显示出来
首先应该在页面中进行引入:以sec为前缀
图片.png
图片.png
7.8 Redis高级数据类型

超级日志和位图:停留来好流弊的样子
他们都可以用来对网站运营的数据进行统计,并且统计过程非常节约内存。
本节课只是了解,下一节课是应用哦。
独立总数:一个用户访问这个网站100次,它的独立总数也只是1。
在RedisTest中进行测试:
-
统计20万个重复数据中的独立总数
图片.png
最终的正确结果应该十万,但是我们得出的结果是99553
-
能够对数据进行合并
将三组数据进行合并,统计合并之后的独立总数。
图片.png
合并之后会产生一个新的key,取名叫做unionkey。

//19833
-
查看一下使用前后内存的变化情况就可以知道使用的内存情况了。它的值只占据12k.
图片.png
-
演示BitMap
-
统计一组数据的boolean数值,然后进行运算。
图片.png
通过Redis底层的连接进行数据的统计,如何获得连接呢?

-
统计三组数据的boolean值,并且对这三组数据做OR运算
把每一组数据都看成是0~6一共7位
图片.png

在上面的这个函数中,第一位首先声明运算符。


7.10 网站数据据统计

- 使用IP进行统计,因为我们不只是关注登录的用户,还有访客。
- 活跃用户统计的是登录的用户。不统计游客。DAU我们要求的结果是比较精确的。
统计uv的时候以天为单位。对于区间则是进行合并。

-
业务层
使用Redis一般不需要写数据访问层。
图片.png
图片.png
可歌可泣,真是艰难啊;

-
统计活跃用户
一周的活跃量是指一周之内只要有一天进行了登录就是活跃的。使用OR运算。
图片.png
图片.png
为啥非得转换成byte[]的类型,真是emmmmm...

- 表现层
由于对于每个请求都要进行记录,因此在拦截器中进行ip的记录。
新建一个拦截器,进行数据的统计
只是统计一下数据,并不要阻挡请求继续向下执行,返回true。

对于2来说,只有登录了才进行统计。

-
配置拦截器
图片.png
-
表现层,展现数据
图片.png
@DateTimeFormat是用来告诉服务器日期的格式。

【*****
关于这个地方我有两个小问题:
1.这个完全可以使用异步请求方式啊,只要在最后不进行刷新就行
- 既然是一个请求,那么完全可以使用param.value来获得开始和结束的日期,不需要非得使用model记录。
*****】
如果最后结尾部分使用的是forword表示声明这个方法只能处理这个请求的一半,还需要另外一个与之平级的方法再进行下一部分的请求处理。这样写能够复用上面那个方法的逻辑。这也是为什么上面的那个方法要加上method= RequestMethod.POST,因为从头到尾只有一个请求,前者是POST请求,转发之后还是。

- 统计活跃用户

-
最后是处理模板
图片.png
按钮是submit!!!也得改。
-
最后,这个功能并不是每一个人都能访问到的。
只有管理人员能够访问。
图片.png
只有使用管理员的身份敲响应的路径才能进行查询,在页面上的任何其他地方是找不到进入data页面的按钮的。

只有一个ip所以访问者是1。

7.13 任务执行和调度

每隔一个小时计算一下服务器上帖子的分数或者计算清除一下临时的文件。
这是由服务器隔一段时间自行进行调度的。
-
线程池
前者是普通的线程池创造的是普通的线程,后者创造的是解决定时任务的线程。
图片.png
在分布式的环境下使用schecule那两个线程池就会有问题,一般使用quarz这个工具。
【解密:为什么在分布式的环境下前面两个会有问题?会有什么问题?为什么quarz没有问题??】
比如删除文件,定时任务在删除之后还会重复产出

前面两个他们的任务是基于内存的,他们的数据不能共享,因此没法解决问题,quartz定时任务的驱动参数不是存储在内存中而是存储在数据库中。只有一份数据库。

这些定时任务会查看数据库中定时任务的状态。如果是等待运行就运行,如果是运行态就放弃运行。
故,我们的目标学会使用quartz。



-
执行定时任务的线程池
图片.png
以上是JDK的线程池
-
spring的线程池
只要我们导入了spring-core它就自动导入了spring的线程池,但是需要在Application中进行配置。
图片.png
对于1来说一共有多少个线程是不确定的,因此有max_size以及core_size。对于2来说,是可以根据系统进行预判的,系统会提前知道大概需要多少个线程,比如有一个线程来计算分数,还有一个来统计数据等,根据预判的结果声明线程数量。

如果将队列都占用满了会怎样,我记得有个老师讲过???但是忘了。

报错了,需要再进行一个配置


这个方法默认是以毫秒为单位。

这两个线程池在使用的时候还有一种简便的调用方式。
在任意一个Bean里面声明一个方法,然后再这个方法上加一个注解,那么它就可以在spring线程池的环境下执行。
举例:
在alphaService中补充代码如下:

这就是为什么在上面的配置文件中还有第三个注解,就是为了让这个注解生效。可以让该方法在多线程的环境下被异步地调用。
-
普通线程池的简化版本
图片.png
-
定时线程池的简化版本
图片.png

接下来就是Quartz了啦~~~
-
建表(以下就是quartz所需要的表)
图片.png
里面一共有11张表,他们都是以qrtz开头。
以下几张比较重要,54分钟左右有详细介绍。
图片.png
-
导包
图片.png
-
quartz中的核心组件以及这些核心组件之间的关系。
Schedular:核心调度工具,底层已经实例化完成了,不需要我们去写。
JOB接口:定义任务
JobDetail:用来配置Job的,
Trigger:触发器,用来配置这个Job什么时候运行,以什么频率反复运行。
当配置好,程序启动的时候,quartz就会读取配置信息。将其读到的配置信息立即存储到数据库中的那些表中,以后就读取表中的数据来执行任务,只要数据初始化到了表中,这些配置就不再使用了,
-
实例演示:
图片.png
接着对job进行配置,这样quartz的底层才能读取配置信息,生成表里的数据,让任务运行起来。
这个配置仅仅是在第一次的时候被读取到然后初始化到数据库中,以后quartz访问数据库调度任务,而不是访问文件了哦。
设置FactoryBean会比直接设置对象更加简单。





至此,任务,任务详情,触发器都已经配置好了。
服务启动之后,默认加载配置,quartz根据配置向数据库中插入数据。数据库中有了数据之后,quartz的底层调度器schedular会根据里面的数据进行调度,三秒一次。
执行正式的项目可以在控制台看到,三秒执行一次。
配置quartz中的线程池(springboot对其有默认配置)。(1:12有详细介绍)

必须进行手动配置,才能存储到数据库中。否则读取的是内存中的数据。
再次运行可以看到表中有了数据。
-
如何删除任务
写一个测试类
删除是通过调度器执行。
图片.png
然后可以发现那几个表里面的数据都没了,除了state和lock,因为里面存储的是schedular调度器和锁还在。
7.16 热帖排行

我们通常是启动一个定时任务进行计算,这样比较高效。
我们在开发的过程中设置为5分钟更新一次分数。不是统一更新所有的帖子,而是将变化的所有帖子放进一个缓存中,定时时间到了之后,就把所有产生变化的帖子计算一下。放进Redis中。

-
在加精,评论或者点赞的时候将post存入redis中。
使用set比较合适。不要使用队列,因为顺序性不是很重要,我们关心重复性的问题。
增加帖子的时候给一个初始分数【为什么我觉得不用啊???】
图片.png
加精:
图片.png
评论:
图片.png
点赞:
图片.png
接下来开始使用到了定时任务:
-
先写一个job
图片.png
图片.png




-
接下来如果这个任务想正常运行,还需要进行一些配置。
图片.png
图片.png

增加一个mode,是为了判断是不是按照热度进行排序。

双击某个名称,右键有一个findUsage可以找到在哪里进行了调用。



-
处理index.html
图片.png
图片.png
7.19 生成长图

一般App这种东西生成长图。
我们探讨的是如何在服务端通过html模板生成一个长图。
工具安装:


配置环境变量
命令演示:
声明本地文件的路径


效果挺不错的哎~~

不希望生成的图片这么大:

一般生成的打卡图片都会比较小,效果也会比较好。
通过java来访问这个工具

1、2两个是异步执行的,1将任务提交给操作系统,然后就接着向下执行了。

因此我们会先看到ok,过了一会儿才会看到生成的图片。
模拟实现实际业务中的分享功能。
- 网页的路径是可配置的
-
文件夹的路径是可配置的,程序运行开始进行检查,如果没有就创建
图片.png

分享功能:
生成图片时间比较长,使用异步的方式。【生成验证码为啥不采用异步的呢??喜喜】

添加了一个share的主题:


-
写一下消费者事件
图片.png
图片.png

获取长图:

测试:

若干小问题
- 可以直接访问静态资源是什么意思,难道是直接可以在浏览器进行访问?不会吧
- 关于登录,我有一个问题,退出时更改某个状态,那么再次登录的时候是又插入一条数据吗??那也太浪费数据库了吧。
3.直接删除不就完事儿了,还触发一个删帖事件,是不是有点麻烦了,小题大做了呢?? - js里面刷新页面是不是再次发送页面请求啊??我觉得是
- 删除,只是在es中进行了删除,但是没有在数据库中进行删除。
- Math.random()的结果是什么。【0,1)确定的。
- 我们可以直接从浏览器中直接访问服务器的静态资源??
8.采用异步生成长图的时候,客户端在干什么呢?虽然说不用等待就可以进行响应,但是图片还是没有生成啊??
网友评论