在上一篇文章中,我们成功地为WebSocket的聊天应用添加了身份验证功能。然而,当时遗留了一个关键问题:当一个新用户加入群聊时,我们希望向群聊内的其他成员发送一条欢迎消息,以告知他们有新朋友加入了。那么,如何实现这一需求呢?
接下来,我们将重点介绍如何使用ChannelInterceptor来实现加入/退出群聊的通知功能。
在上一篇文章中,我们成功地为WebSocket的聊天应用添加了身份验证功能。然而,当时遗留了一个关键问题:当一个新用户加入群聊时,我们希望向群聊内的其他成员发送一条欢迎消息,以告知他们有新朋友加入了。那么,如何实现这一需求呢?
接下来,我们将重点介绍如何使用ChannelInterceptor来实现加入/退出群聊的通知功能。
上一篇博文介绍了如何利用STOMP和SpringBoot搭建一个能够实现相互通讯的聊天系统。通过该系统,我们了解了STOMP的基本使用方法以及一些基础概念。接下来,我们将在此基础上进行一些增强。由于聊天的本质是交流,因此我们需要知道是谁在与谁进行聊天,这就需要登录功能的支持。
接下来,我们将探讨如何为WebSocket通信添加身份验证功能。
在我们的日常工作中,我们可能会遇到需要实现双向通讯的场景。为了解决这个问题,常见的实现方案包括短轮询、长轮询、SSE和WebSocket等几种方式。本文将重点介绍如何通过整合WebSocket和STOMP协议来实现双向通讯的方案, 并给出一个应用实例,带你轻松掌握如何基于SpringBoot搭建一个在线聊天系统
本文将介绍一个SpringBoot进阶技巧:压缩返回结果实例演示,旨在提升您的网站访问性能。
当返回的数据较大时,网络开销通常不可忽视。为了解决这个问题,我们可以考虑压缩返回的结果,以减少传输的数据量,从而降低网络开销并提高性能。对于依赖Spring生态的Java开发者来说,幸运的是SpringBoot提供了非常便捷的使用方式。
接下来,我们将介绍几种不同情况下的压缩返回的使用方式:
关于SpringBoot的自定义配置源、配置刷新之前也介绍过几篇博文;最近正好在使用apollo时,排查配置未动态刷新的问题时,看了下它的具体实现发现挺有意思的;
接下来我们致敬经典,看一下如果让我们来实现配置的动态刷新,应该怎么搞?
javascript以64位双精度浮点数存储所有Number类型值,即计算机最多存储64位二进制数。 但是需要注意的是Number包含了我们常说的整形、浮点型,相比较于整形而言,会有一位存储小数点的偏移位,由于存储二进制时小数点的偏移量最大为52位,计算机存储的为二进制,而能存储的二进制为62位,超出就会有舍入操作,因此 JS 中能精准表示的最大整数是 Math.pow(2, 53),十进制即9007199254740992 大于9007199254740992的可能会丢失精度
因此对于java后端返回的一个大整数,如基于前面说到的雪花算法生成的id,前端js接收处理时,就可能出现精度问题
接下来我们以Thymeleaf模板渲染引擎,来介绍一下对于大整数的精度丢失问题的几种解决方案
系统唯一ID是我们在设计一个系统的时候常常会遇见的问题,比如常见的基于数据库自增主键生成的id,随机生成的uuid,亦或者redis自增的计数器等都属于常见的解决方案;本文我们将会重点看一下业界内大名鼎鼎的雪花算法,是如何实现分布式id的
sql日志打印,再我们日常排查问题时,某些时候帮助可以说是非常大的,那么一般的Spring项目中,可以怎么打印执行的sql日志呢?
本文将介绍三种sql日志打印的方式:
再传统的基于session的用户身份认证方式之中,用户相关信息存储与后端,通常基于cookie来携带用户的会话id,然后后端在基于会话id查到对应的用户身份信息;区别于session的身份认证方式,jwt作为一个基于RFC 7519的开发标准,提供了一种通过JSON形式的web令牌,用于在各系统之间的安全可信的数据传输、身份标识
本文将主要介绍jwt的相关知识点,以及如何基于jwt来实现一个简单的用户鉴权方案
jwt,全称 json web token, JSON Web 令牌是一种开放的行业标准 RFC 7519 方法,用于在两方之间安全地表示声明。
详情可以参考: hhttps://jwt.io/introduction
JSON Web Token由三部分组成,它们之间用圆点.进行分割, 一个标准的JWT形如 xxx.yyy.zzz
即第一部分,由两部分组成:token的类型(JWT)和算法名称(比如:HMAC SHA256或者RSA等等)。
一个具体实例如
1 | { |
然后,用Base64对这个JSON编码就得到JWT的第一部分
第二部分具体的实体,可以写入自定义的数据信息,有三种类型
Registered claims : 这里有一组预定义的声明,它们不是强制的,但是推荐。比如:iss (issuer 签发者), exp (expiration time 有效期), sub (subject), aud (audience)等。Public claims : 可以随意定义。Private claims : 用于在同意使用它们的各方之间共享信息,并且不是注册的或公开的声明如一个具体实例
1 | { |
对payload进行Base64编码就得到JWT的第二部分
为了得到签名部分,你必须有编码过的header、编码过的payload、一个秘钥,签名算法是header中指定的那个,然对它们签名即可。
如 HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
签名是用于验证消息在传递过程中有没有被更改,并且,对于使用私钥签名的token,它还可以验证JWT的发送方是否为它所称的发送方。
下面给出一个基于 java-jwt 生成的具体实例
1 | public static void main(String[] args) { |

接下来我们基于jwt方案实现一个用户鉴权的示例demo
首先搭建一个标准的SpringBoot项目工程,相关版本以及依赖如下
本项目借助SpringBoot 2.2.1.RELEASE + maven 3.5.3 + IDEA进行开发
添加web支持,用于配置刷新演示
1 | <dependencies> |
我们采用thymeleaf来进行前端页面的渲染,添加一些相关的配置 application.yml
1 | server: |
一个简单的基于jwt的身份验证方案如下图

基本流程分三步:
用户登录成功之后,后端将生成的jwt返回给前端,然后前端将其保存在本地缓存;
之后前端与后端的交互时,都将jwt放在请求头中,我们这里借助Http的身份认证的请求头Authorization
后端接收到用户的请求,从请求头中获取jwt,然后进行校验,通过之后,才响应相关的接口;否则表示未登录
基于上面的流程,我们可以实现一个非常简单的登录认证演示工程
首先在内存中,维护几个简单用户名/密码信息,用于模拟用户名+密码的校验
1 |
|
然后提供登录接口
1 |
|
上面的接口实现,接收两个请求参数: 用户名 + 密码
当用户身份校验通过之后,将生成一个jwt,这里直接使用开源项目java-jwt来生成(当然有兴趣的小伙伴也可以自己来实现)
需要注意的一点是,我们在上面的实现中,除了直接返回jwt之外,也将这个jwt写在cookie中,这种将jwt写入cookie的方案,主要的好处就是前端不需要针对jwt进行特殊处理
当然对应的缺点也和直接使用session的鉴权方式一样,存在csrf风险,以及对于跨资源共享时的资源共享问题(CORS)
本项目的实际演示中,采用前端存储返回的jwt,然后通过请求头方式来传递jwt
上面登录完成之后,再提供一个简单的要求登录之后才能查看的查询接口
1 |
|
最后再写一个前端页面来完成整个测试
1 |
|
对应的前端页面如下:
1 |
|
基于上面的实现,接下来我们看一下具体表现情况


从上面的两张图也可以看出,登录成功之后,jwt写入到本地的session storage中,再后续的请求中,若请求头Authroization中携带了jwt信息,则后端可以进行正常校验
有兴趣的小伙伴可以尝试修改一下本地存储中的jwt值,看一下非法或者过期的jwt会怎么表现
本文主要介绍了jwt的基本知识点,并给出了一个基于jwt的使用实例,下面针对jwt和session做一个简单的对比
| jwt | session |
|---|---|
| 前端存储,通用的校验规则,后端再获取jwt时校验是否有效 | 前端存索引,后端判断session是否有效 |
| 验签,不可篡改 | 无签名保障,安全性由后端保障 |
| 可存储非敏感信息,如用户名,头像等 | 一般不存储业务信息 |
| jwt生成时,指定了有效期,本身不支持续期以及提前失效 | 后端控制有效期,可提前失效或者自动续期 |
| 通常以请求头方式传递 | 通常以cookie方式传递 |
| 可预发csrf攻击 | session-cookie方式存在csrf风险 |
关于上面的两个风险,给一个简单的扩展说明
csrf攻击
如再我自己的网站页面上,添加下面内容
1 | <img src="https://paicoding.com/logout" style="display:none;"/> |
然后当你访问我的网站时,结果发现你在技术派上的登录用户被注销了!!!
使用jwt预防csrf攻击的主要原理就是jwt是通过请求头,由js主动塞进去传递给后端的,而非cookie的方式,从而避免csrf漏洞攻击
尽信书则不如,以上内容,纯属一家之言,因个人能力有限,难免有疏漏和错误之处,如发现bug或者有更好的建议,欢迎批评指正,不吝感激
下面一灰灰的个人博客,记录所有学习和工作中的博文,欢迎大家前去逛逛

使用过SpringBoot应用的小伙伴应该对它配套的配置文件application.yml不会陌生,通常我们将应用需要的配置信息,放在配置文件中,然后再应用中,就可以通过 @Value 或者 @ConfigurationProperties来引用
那么配置信息只能放在这些配置文件么? 能否从db/redis中获取配置信息呢? 又或者借助http/rpc从其他的应用中获取配置信息呢?
答案当然是可以,比如我们熟悉的配置中心(apollo, nacos, SpringCloudConfig)
接下来我们将介绍一个不借助配置中心,也可以实现自定义配置信息加载的方式,并且支持配置的动态刷新
SpringBoot中极大的简化了项目中对于属性配置的加载方式,可以简单的通过 @Value, @ConfigurationProperties 来实现属性配置与Java POJO对象、Bean的成员变量的绑定,那如果出现一个某些场景,需要我们手动的、通过编程式的方式,将属性配置与给定的pojo对象进行绑定,我们又应该怎么实现呢?
很多pc网站都有一个实时在线人数的统计功能,那么一般这种是采用什么方式来实现的呢? 这里我们介绍一个最基础的是实现方式,基于Session结合WebListener来实现在线人数统计