1208 字
6 分钟
Redis05-短信登陆
2023-07-03
2023-11-28
无标签

短信登陆#

导入的表格#

  • tb_user:用户表
  • tb_userLinfo:用户详情表
  • tb_shop:商户信息表
  • tb_shop_type:商户类型表
  • tb_blog:用户日记表(达人探店日记)
  • tb_follow:用户关注表
  • tb_voucher:优惠券表
  • tb_voucher_order:优惠券的订单表

短信登录的关键不在页面外观,而在验证码与用户身份的衔接:服务端保存与手机号对应的验证码,登录请求提交后进行比对,通过后再查找或创建用户并建立登录态。验证码只是一次登录校验材料,不应作为长期凭证,也不应把用户表中的全部字段交给浏览器。

为什么使用Redis#

实例内 Session 与 Redis 共享登录态对照

Session 保存在各自应用实例内存时,一个实例不能直接读到另一个实例的登录记录。改用 Redis 保存登录态后,请求携带随机 token,各实例都能通过它查找同一份用户信息;这改变的是状态存储位置,并不意味着浏览器会自动保存或发送新的凭证。

1.怎么基于session

2.验证码如何比对

3.是否要将所有的数据存入session?

==集群的session共享问题==

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

session的替代方案应该满足:

  • 数据共享
  • 内存存储
  • kev、value结构(和session一样)

使用Redis!

首先每个Tomcat可以去访问Redis,Redis是内存存储的,且Redis就是key,value结构

问题:

  • 保存验证码

存储在Redis中类型:String,那么key是什么?手机号(确保每个手机号有自己的验证码,不仅可以

  • 保存用户信息

存储在Redis中类型:Hash,那么key是什么?==手机号(不推荐,放在请求头中,有暴露的风险) 建议随机token==

(保存登录的用户信息,可以使用String结构,以SON字符串来保存,比较直观,

Hash结构可以将对象中的每个字段独立存储,可以针对单个字段做CRUD,并且内存占用更少)

  • 登陆校验

不再是sessionid,token才是登录凭着,但是token不是自动存储在浏览器,需要手动返回到浏览器。

验证码可以按手机号建立独立的 String 键,登录用户信息则以随机 token 为索引保存为 Hash,或按需要序列化为 String。登录成功后把 token 返回客户端,由后续请求显式携带;验证码和登录态分别设置有效期,既限制凭证使用窗口,也避免过期记录长期占用内存。

==可以给验证码设置有效期,放在内存满==

==注意像session(默认30min)一样给登陆时间做一个有效期,要不然登陆信息越来越多,最后会把redis装满==

==另一个问题,有效期30min,从登陆开始算起,只要登陆了30min后就会踢出,那么如何访问刷新有效期?拦截器!==

==上个问题可以在prehandle中修改,获取请求头的token,

preHandle
调用时间:Controller方法处理之前
执行顺序:链式Intercepter情况下,Intercepter按照声明的顺序一个接一个执行
若返回false,则中断执行,注意:不会进入afterCompletion
postHandle
调用前提:preHandle返回true
调用时间:Controller方法处理完之后,DispatcherServlet进行视图的渲染之前,也就是说在这个方法中你可以对ModelAndView进行操作
执行顺序:链式Intercepter情况下,Intercepter按照声明的顺序倒着执行。
备注:postHandle虽然post打头,但post、get方法都能处理
afterCompletion
调用前提:preHandle返回true
调用时间:DispatcherServlet进行视图的渲染之后

Redis代替session需要考虑的问题:

  • 选择合适的数据结构
  • 选择合适的key
  • 选择合适的存储粒度

==拦截器问题==

拦截器拦住了需要登录的路径,若一直访问不需要登陆的网页则不会刷新,怎么办?

刷新登录态与路径登录校验的拦截器顺序

将刷新拦截器放在前面并覆盖所有路径,有有效 token 才恢复用户信息、刷新登录态有效期;随后由登录拦截器检查受保护路径。公开路径无需登录,但有效登录用户访问这些路径时仍能完成续期。缺少或失效的凭证不能通过刷新重新获得登录身份。

如何控制拦截器顺序?

.order属性

例如:

@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new RefreshTokenInterceptor(stringRedisTemplate))
.addPathPatterns(
"/**"
).order(0);
registry.addInterceptor(new LoginInterceptor())
.excludePathPatterns(
"/shop/**",
"/blog/hot",
"/shop/type/**",
"/upload/**",
"/vocher/**",
"/user/code",
"/user/login"
).order(1);
}

order越小越先执行