1. Spring Security
介绍
- 简介
- Spring Security是一个专注与为Java应用程序提供身份认证和授权的框架,它的强大之处在于它可以轻松扩展以满足自定义的需求。
- 特征
- 对身份的认证和授权提供全面的、可扩展的支持。
- 防止各种攻击,如会话固定攻击、点击劫持、csrf攻击等。
- 支持与Servelt API、Spring MVC等Web技术集成。
- https://spring.io/projects/spring-security
- 原理
- 底层使用Filter(javaEE标准)进行拦截
- Filter—>DispatchServlet—>Interceptor—>Controller(后三者属于Spring MVC)
推荐学习网站:www.spring4all.com
导包:spring-boot-starter-security
- User实体类实现UserDetails接口,实现接口中各方法(账号、凭证是否可用过期,管理权限)
- UserService实现UserDetailsService接口,实现接口方法(security检查用户是否登录时用到该接口)
- 新建SecurityConfig类
- 继承WebSecurityConfigurerAdapter
- 配置忽略静态资源的访问
- 实现认证的逻辑,自定义认证规则(AuthenticationManager: 认证的核心接口)
- 登录相关配置
- 退出相关配置
- 委托模式: ProviderManager将认证委托给AuthenticationProvider.ProviderManager持有一组AuthenticationProvider,每个AuthenticationProvider负责一种认证
- 实现授权的逻辑
- 授权配置,设置自己的登录页面
- 增加Filter,处理验证码
- 记住我
- 重定向,浏览器访问A,服务器返回302,建议访问B.一般不能带数据给B(Session和Cookie)
- 地址栏变化
- 转发,浏览器访问A,A完成部分请求,存入Request,转发给B完成剩下请求。(有耦合)
- 地址栏不变化
在HomeController添加认证逻辑
之前采用拦截器实现了登录检查,这是简单的权限管理方案,现在将废弃。
对当前系统内的所有的请求,分配访问权限(普通用户、板主、管理员)。
绕过Security认证流程,采用系统原来的认证方案。
防止CSRF攻击的基本原理,以及表单、AJAX的相关配置。
- CSRF攻击:某网站盗取你的Cookie(ticket)凭证,模拟你的身份访问服务器,用表单提交数据,获取利益。(发生在提交表单的时候)
- Security会在表单里增加一个TOCKEN(自动生成)
- 异步请求Security无法处理,在html文件生成CSRF令牌,(异步不是通过请求体传数据,通过请求头)
- 发送AJAX请求之前,将CSRF令牌设置到请求的消息头中.(每个异步请求都需要处理)
- 项目中禁用了CSRF攻击的检查
3. 置顶、加精、删除
功能实现
点击“置顶”、“加精”、“删除”,修改帖子的状态
版主可以执行“置顶”、“加精”操作。管理员可以执行“删除”操作。
- 在SecurityConfig类下配置,置顶、加精、删除的访问权限。
按钮显示
- 版主可以看到“置顶”、“加精”按钮。管理员可以看到“删除“按钮。
- 导包:thymeleaf-extras-springsecurity5,thymeleaf对security的支持。
4. Redis高级数据类型
HyperLoglog(超级日志)
- 采用一种基数算法,用于完成独立总数的统计。
- 占据空间小,无论统计多少个数据,只占12K的内存空间。
-
Bitmap
不是一种独立的数据结构,实际上就是字符串。
- 支持按位存取数据,可以将其看成是byte数组。
-
5. 网站数据统计
UV(Unique Visitor)
独立访客,需通过用户IP排重新统计数据。
- 每次访问都要进行统计。
-
DAU(Daily Active User)
日活跃用户,需通过用户ID排重新统计数据。(不统计游客)
- 访问过一次,则认为其为活跃。QW
-
实现步骤
新建DataService类进行统计操作。
- 表现层一分为二,首先是何时记录这个值,其次是查看。
- 每次请求都要记录值,因此记录值在拦截器写比较合适DataInterceptor
- 查看值DataController
- 返回时使用forward转发,表明当前请求仅完成一半,还需另外一个方法继续处理请求。
-
6. 任务执行和调度
JDK线程池
ExecutorService
ScheduledExecutorService(可以执行定时任务)
Spring 线程池
ThreadPoolTaskExecutor
- ThreadPoolTaskScheduler(分布式环境可能出问题)
- 执行定时任务时,由多个服务器会产生重复和冲突
分布式定时任务
- Spring Quartz(将数据存储到数据库,分布式时可以共享数据)
- 核心调度接口Scheduler
- 定义任务的接口Job的execute方法
- Jobdetail接口来配置Job的名字、组等
- Trigger接口配置Job的什么时候运行、运行频率
- QuartzConfig:配置 -> 数据库 -> 调用(配置类在启动后,将数据存入数据库,Quartz的底层scheduler进行调度)
- FactoryBean可简化Bean的实例化过程:
- 通过FactoryBean封装Bean的实例化过程
- 将FactoryBean装配到Spring容器里
- 将FactoryBean注入给其他的Bean.
- 该Bean得到的是FactoryBean所管理的对象实例.
http://www.quartz-scheduler.org
7. 热帖排行
Nowcoder
- log(精华分 + 评论数 10 + 点赞数 2)+(发布时间 - 牛客纪元)
- log给前期的精华,点赞评论等加大权重,时间越短,热度往往越高
- 在发帖、点赞、加精时计算帖子分数(*Controller层,将变换的帖子存入Redis中,存入set中(需要去重,但不关注顺序))
- 每隔一段时间再进行计算
- 定义任务PostScoreRefreshJob(计算分数,更新到数据库和ES服务器)
- 进行配置QuartzConfig
- 每隔一段时间再进行计算
展示(添加按照热度的排序)
wkhtmltopdf url file
- wkhtmltoimage url file
- log(精华分 + 评论数 10 + 点赞数 2)+(发布时间 - 牛客纪元)
- java
- Runtime.getRuntime().exec()
步骤
- 配置wk生成图片存放的位置WkConfig
由于生成图片的时间比较长,因此采用kafka实现消费
客户端将数据提交给云服务器,并等待其响应。
- 用户上传头像时,将表单数据提交给云服务器。
步骤:
应用服务器将数据直接提交给云服务器,并等待其响应。
- 分享时,服务端将自动生成的图片,直接提交给云服务器。
- 步骤
- 修改Controller层返回到前端的路径ShareController
- 修改kafka消费事件,将图片直接上传到七牛云服务器EventConsumer
- 采用ThreadPoolTaskScheduler实现定时查看图片是否生成,生成后上传,设置上传失败的条件
10. 优化网站性能
缓存
- 本地缓存
- 将数据缓存在应用服务器上,性能最好。
- 常用缓存工具:Ehcache、Cuava、Caffeine等。
- 本地缓存不会存储用户强关联性的信息
- 分布式缓存
- 将数据缓存在NoSQL数据库上,跨服务器。
- 常用缓存工具:MemCache、Redis等。
- 多级缓存
- ->一级缓存(本地缓存)->二级缓存(分布式缓存)-> DB
- 避免缓存雪崩(缓存失效,大量请求直达DB),提高系统的可用性。
- 本地缓存空间比较小
优化热帖
- 初始化Caffeine缓存:可以从二级缓存中取也可以从数据库中取,项目启动后立即初始化
- 查询:先到Caffeine缓存中取,再到Redis缓存中取,再到数据库中取DiscussPostService
- 添加缓存和不添加缓存的情况对比
- 环境:在DB中添加30万条帖子数据
- 工具:JMeter进行压力测试
- 观察数据:吞吐量
- 实验数据