短信登陆
导入的表格
- tb_user:用户表
- tb_userLinfo:用户详情表
- tb_shop:商户信息表
- tb_shop_type:商户类型表
- tb_blog:用户日记表(达人探店日记)
- tb_follow:用户关注表
- tb_voucher:优惠券表
- tb_voucher_order:优惠券的订单表
短信登录的关键不在页面外观,而在验证码与用户身份的衔接:服务端保存与手机号对应的验证码,登录请求提交后进行比对,通过后再查找或创建用户并建立登录态。验证码只是一次登录校验材料,不应作为长期凭证,也不应把用户表中的全部字段交给浏览器。
为什么使用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属性
例如:
@Overridepublic 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越小越先执行