开发短信验证登录功能
开发流程:

发送短信模块
当点击我的之后会弹出登录页面,要求输入手机号获取验证码,当输入手机号点击发送验证码后,通过抓包发现浏览器会发送如下报文
可以看到,浏览器会以post方式向服务器发送请求,并携带请求参数:phone=xxx。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public Result sendCode(String phone, HttpSession session){ boolean phoneInvalid = RegexUtils.isPhoneInvalid(phone); if(phoneInvalid){ return Result.fail("手机号不合法,请重新输入"); } String code = RandomUtil.randomNumbers(6); session.setAttribute("code",code); log.debug("成功发送验证码:" + code); return Result.ok(); }
|
登录模块
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
|
public Result login(LoginFormDTO loginFormDTO,HttpSession session){ String phone = loginFormDTO.getPhone(); if(RegexUtils.isPhoneInvalid(phone)){ return Result.fail("手机号格式错误"); } String code = loginFormDTO.getCode(); String cachecode = (String)session.getAttribute("code"); if(code == null || !cachecode.equals(code)){ return Result.fail("验证码错误"); } User user = query().eq("phone", phone).one(); if(user == null){ user = createUserWithPhone(phone); save(user); } session.setAttribute("user",user); return Result.ok(); }
|
校验登录

问题:拦截器和过滤器有什么区别?拦截器的作用是什么?为什么要使用ThreadLocal?详细介绍一下ThreadLocal?
拦截器是SpringMVC中提供的类,也是用于拦截请求,和过滤器不同的是,它拦截的是DispatcherServlet和控制器方法之间的请求。而过滤器拦截的是用户和Servlet间的请求。而且过滤器是基于Servlet的,它只能用于web程序,而拦截器是Spring的组件,由Spring控制,不仅能用于web程序,还能用于其他程序。
拦截器是基于java反射机制(动态代理实现的),而过滤器是基于回调函数(doFilter方法)实现的,当一个过滤器执行完后,会调用doFilter方法返回执行上一级Filter
鉴于两者都能够拦截请求,因此常被用来作为鉴权登录模块
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| package com.hmdp.utils;
import com.hmdp.entity.User; import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession;
public class UserLoginInteceptorHandler implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { HttpSession session = request.getSession(); User user = (User) session.getAttribute("user"); if(user == null){ response.setStatus(401); return false; } UserHolder.saveUser(user); return true; }
@Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { UserHolder.removeUser(); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| package com.hmdp.config;
import com.hmdp.utils.UserLoginInteceptorHandler; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration public class InceptorConfig implements WebMvcConfigurer {
@Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new UserLoginInteceptorHandler()) .excludePathPatterns( "/user/login", "/user/code", "/blog/hot", "/shop/**", "/shop-type/**", "/voucher/**", "/voucher-order/**" ); } }
|
如何保护用户敏感信息

从图中可以看出,当前系统中,当我们登录时,会将用户的一些敏感信息暴露在浏览器中,这非常危险。因此我们需要解决该问题,那么常用的解决方案就是,定义两个用户实体,一个是数据库用户实体,另一个是返回给浏览器的用户实体,后者相对于前者缺少了用户的敏感信息,更加安全,如下图所示。
