短信登录1. 基于 Session 实现短信登录完整流程接口拦截器拦截到用户信息后保存到 ThreadLocal 中。因为ThreadLocal 它是一个线程域对象每一个进如 Tomcat 的请求都是一个独立的线程将来 ThreadLocal 就会在线程中开辟一个内存的空间去保存对应的用户这样一来每个用户互相不干扰。为什么要使用拦截器校验登录状态好处统一管理所有登录检查在一个地方完成代码复用不用在每个Controller方法里都写检查逻辑职责清晰业务代码只关心业务不关心权限检查易于维护修改登录规则只需改一处为什么要用 ThreadLocal 保存用户信息在Web服务器中的问题Tomcat服务器有线程池多个请求可能复用同一个线程如果用普通变量存储用户信息会发生数据混乱A用户的信息可能被B用户看到严重的安全问题注意使用 ThreadLocal 必须清理如果不清理线程被放回线程池后下一个请求可能会拿到上一个用户的信息造成严重的隐私泄露ThreadLocal 的真实存储结构服务器上有多个线程(处理多个用户请求): 线程1 (处理用户A的请求) └─ ThreadLocalMap (线程私有的) └─ key: ThreadLocal对象 └─ value: UserDTO(id1, nickName张三, iconxxx) 线程2 (处理用户B的请求) └─ ThreadLocalMap (线程私有的) └─ key: ThreadLocal对象 └─ value: UserDTO(id2, nickName李四, iconyyy) 线程3 (处理用户C的请求) └─ ThreadLocalMap (线程私有的) └─ key: ThreadLocal对象 └─ value: UserDTO(id3, nickName王五, iconzzz)关键点:每个线程都有自己的ThreadLocalMap- 不是共享一个大 MapThreadLocalMap 是 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类型 MapString, Object userMap BeanUtil.beanToMap(userDTO,new HashMap(), CopyOptions.create() .setIgnoreNullValue(true) //对于每个字段不管它原来是什么类型都给我转成字符串 .setFieldValueEditor((fieldName, fieldValue) - fieldValue.toString()));登录拦截器优化