短信登录

1. 基于 Session 实现短信登录

完整流程:

接口:


拦截器拦截到用户信息后保存到 ThreadLocal 中。因为ThreadLocal 它是一个线程域对象,每一个进如 Tomcat 的请求都是一个独立的线程,将来 ThreadLocal 就会在线程中开辟一个内存的空间去保存对应的用户,这样一来每个用户互相不干扰。

为什么要使用拦截器校验登录状态?

好处:

统一管理:所有登录检查在一个地方完成

代码复用:不用在每个Controller方法里都写检查逻辑

职责清晰:业务代码只关心业务,不关心权限检查

易于维护:修改登录规则只需改一处


为什么要用 ThreadLocal 保存用户信息?

在Web服务器中的问题:

Tomcat服务器有线程池,多个请求可能复用同一个线程

如果用普通变量存储用户信息,会发生数据混乱

A用户的信息可能被B用户看到(严重的安全问题!)

注意: 使用 ThreadLocal 必须清理,如果不清理,线程被放回线程池后,下一个请求可能会拿到上一个用户的信息,造成严重的隐私泄露!

💻 ThreadLocal 的真实存储结构

服务器上有多个线程(处理多个用户请求):

线程1 (处理用户A的请求)
  └─ ThreadLocalMap (线程私有的)
      └─ key: ThreadLocal对象
          └─ value: UserDTO(id=1, nickName="张三", icon="xxx")

线程2 (处理用户B的请求)
  └─ ThreadLocalMap (线程私有的)
      └─ key: ThreadLocal对象
          └─ value: UserDTO(id=2, nickName="李四", icon="yyy")

线程3 (处理用户C的请求)
  └─ ThreadLocalMap (线程私有的)
      └─ key: ThreadLocal对象
          └─ value: UserDTO(id=3, nickName="王五", icon="zzz")

关键点:

每个线程都有自己的 ThreadLocalMap - 不是共享一个大 Map

ThreadLocalMap 是 Thread 类的一个成员变量 - 属于线程私有

不同线程之间互不干扰 - 线程1拿不到线程2的数据

使用 UserDTO 类隐藏敏感信息。


2. 基于 Redis 实现共享 Session 登录

session 共享问题

多台 Tomcat 并不共享 session 存储的空间,当请求切换到不同的 Tomcat 服务时导致数据丢失的问题。

Session 的替代方案应该满足:

  • 数据共享
  • 内存存储
  • key、value 结构

对于验证码存储的 key 选择:

以手机号为 key 存储验证码

以手机号为 key 读取验证码

对于保存用户的 key 选择:

以随机的 token 为 key 存储用户数据

有两种选择:

第一:使用 String 结构,以 JSON 字符串来保存,优点比较直观

第二:使用 Hash 结构,将对象中的每个字段独立存储,可以针对单个字段做 CRUD,优点内存占用更少(本项目的选择方案)

对于前端代码对 token 的保存和访问携带的实现代码:

随机 Token 不可预测、更安全、更灵活

部分代码:

//TODO 这里的userDTO 里面的id 是Long类型,存入Redis中需要转换为String类型
        Map<String, Object> userMap = BeanUtil.beanToMap(userDTO,new HashMap<>(),
                CopyOptions.create()
                        .setIgnoreNullValue(true)
                        //对于每个字段,不管它原来是什么类型,都给我转成字符串
                        .setFieldValueEditor((fieldName, fieldValue) -> fieldValue.toString()));

登录拦截器优化

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐