基于Redis进行登录校验
创始人
2024-03-30 13:22:53
0

本文从前端讲解数据流转过程

【前端如下】:首先输入手机号并点击发送验证码,将手机号数据进行提交到服务器

【服务器】如下:客户端 发送的请求和携带的数据【手机号】12345678910。

【第一步】首先会被拦截器拦截,这里配置了两个拦截器,根据拦截器拦截内容,第一个拦截器会进行释放,第二个拦截器由于拦截范围原因也会进行释放。

 【第二步】数据【手机号】12345678910,会流转到验证码发送业务。

  • 首先判断手机号是否符合要求
  • 生成验证码
  • Redis进行全局数据缓存,将验证码信息缓冲到Redis当中 
@Overridepublic Result sendCode(String phone, HttpSession session) {// 1. 验证手机号if (RegexUtils.isPhoneInvalid(phone)) {// 如果不符合要求直接返回return Result.fail("手机号不正确");}// 2.生成验证码String code = RandomUtil.randomNumbers(6);// 3.保存验证码到Redis中--验证码设置过期时间为60stemplate.opsForValue().set(LOGIN_CODE_KEY + phone, code, LOGIN_CODE_TTL, TimeUnit.MINUTES);// 4.发送验证码log.debug("验证码是:{}", code);return Result.ok();}

【第三步】用户点击登录按钮,数据【手机号+验证码】都会流转到登录业务

  • 首先进行手机号和 验证码的校验。
  • 如果校验成功判断是否是新用户
  • 如果是新用户,则将信息添加到 数据库中
  • 然后将用户信息存入Redis,采用的是Hash结构,注意设置过期时间和数据类型的转换。
  • 将生成的TokenKey返回给前端。
@Overridepublic Result login(LoginFormDTO loginForm, HttpSession session) {// 1. 验证手机号String phone = loginForm.getPhone();if (RegexUtils.isPhoneInvalid(phone)) {return Result.fail("手机号格式错误");}// 2. 从Redis中获取验证码String code = template.opsForValue().get(LOGIN_CODE_KEY + phone);if (code == null || !code.equals(loginForm.getCode())) {return Result.fail("验证码错误");}// 3.根据手机号查询用户信息User user = query().eq("phone", phone).one();// 4. 用户不存在则创建用户到数据库if (user == null) {user = CreateNewUser(phone);}// 5.保存用户到RedisString token = UUID.randomUUID(false).toString();UserDTO userDTO = BeanUtil.copyProperties(user, UserDTO.class);// 设置Long类型的数据转换为字符串类型的。Map userMap = BeanUtil.beanToMap(userDTO, new HashMap<>(),CopyOptions.create().setIgnoreNullValue(true).setFieldValueEditor((fieldName,fieldValue)->fieldValue.toString()));String tokenKey = LOGIN_USER_KEY + token;template.opsForHash().putAll(tokenKey,userMap);template.expire(tokenKey,LOGIN_USER_TTL,TimeUnit.MINUTES);// 6.返回Tokenreturn Result.ok(token);}private User CreateNewUser(String phone) {User user = new User();user.setPhone(phone);user.setNickName(USER_NICK_NAME_PREFIX + RandomUtil.randomString(6));save(user);return user;}

【第四步】登录状态校验

首先数据会被我们之前提到的拦截器进行拦截

  • 获取上一步存入Redis中用户的信息,
  • 将信息转为DTO对象
  • 将对象保存在ThreadLocal中,保证线程安全,
  • 然后对Redis数据的有效期进行刷新

第一个拦截器代码如下:

package com.hmdp.utils;import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.hmdp.dto.UserDTO;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
import java.util.concurrent.TimeUnit;import static com.hmdp.utils.RedisConstants.LOGIN_USER_KEY;
import static com.hmdp.utils.RedisConstants.LOGIN_USER_TTL;public class RefleshInterceptor implements HandlerInterceptor {private StringRedisTemplate template;public RefleshInterceptor(StringRedisTemplate template) {this.template = template;}@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 1.获取tokenString token = request.getHeader("authorization");if (StrUtil.isBlank(token)) {return true;}String tokenKey = LOGIN_USER_KEY + token;Map userMap = template.opsForHash().entries(tokenKey);// 2.判断用户是否存在if (userMap.isEmpty()) {return true;}// 3. 获取用户并转换为UserDTOUserDTO userDTO = BeanUtil.fillBeanWithMap(userMap, new UserDTO(), false);//4.存在保存到ThreadLocalUserHolder.saveUser(userDTO);// 5. 刷新token的有效期template.expire(tokenKey, LOGIN_USER_TTL, TimeUnit.MINUTES);return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {UserHolder.removeUser();}
}

【第五步】

从第一个拦截器中出来以后,会进入第二个拦截器

  • 检查是否有用户信息
  • 如果不存在则直接拦截
  • 存在则放行

至此所有登录相关校验执行关闭。

package com.hmdp.utils;import com.hmdp.dto.UserDTO;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class LoginInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 1. 查询ThreadLocalUserDTO user = UserHolder.getUser();if (user == null) {// 不存在拦截response.setStatus(401);return false;}return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {UserHolder.removeUser();}
}

【完整流程图如下】:首先进行短信验证码登录,注册--->校验登录状态。 

 

相关内容

热门资讯

落户政策居然考虑放开! 怎么,我能落户北京了? 大家好,我是孙少睡,这是我的第467篇楼市评论。 很多人的第一反应肯定是有没...
股市必读:ST泉为股东因涉嫌违... 截至2025年12月26日收盘,ST泉为(300716)报收于9.96元,下跌0.8%,换手率0.9...
日本公布犯罪白皮书:2024年... 日本法务省19日公布的2025年版犯罪白皮书显示,日本2024年刑事犯罪案件数量明显上升,其中性犯罪...
中央广电总台副台长王晓真,黑龙... 据央视新闻报道,12月28日,中央广播电视总台《2026年春节联欢晚会》分会场发布。黑龙江哈尔滨、浙...
聚焦全国财政工作会议丨明年财政... (央视财经《经济信息联播》)明年是“十五五”规划的开局之年,财政政策将聚焦哪些关键领域精准发力? ...
原创 中... 12月26日,中国对美国实施了一次重磅反制,针对美国政府前不久批准的111亿美元对台军售,中方决定出...
徐杰11分王少杰遭驱逐 张宁缺... [搜狐体育战报]北京时间12月28日消息,2025-26赛季CBA常规赛继续第7轮角逐。王少杰第三节...
《今日说法》主持人李晓东买茶叶... 12月28日,《今日说法》栏目主持人李晓东发布视频称,此前“被骗1000元买茶叶”事件迎来新进展:该...
3-0领先终于能休息了!莫德里... 在意甲第17轮的一场焦点战中,AC米兰迎战维罗纳。比赛进行到第70分钟时,AC米兰在3-0领先的情况...