登录功能
基于Session实现短信登录
发送验证码
校验验证码、注册
创建线程池
public class UserHolder {
private static ThreadLocal<User> tl =new ThreadLocal<User>();
// 存数据
public static void saveUser(User user){
tl.set(user);
}
//取数据
public static User getUser(){
return tl.get();
}
//删除数据
public static void removeUser(){
tl.remove();
}
}
登录校验拦截器
由于有些方法需要在发送请求时校验登录状态(即登录后才能发送请求),而不同的业务接口如果各自写登录校验会冗余,所以使用一个全局的登录拦截器进行拦截,同时记录下登录的状态信息,以便后续使用
定义登录拦截器
配置拦截器生效
选择放行哪些方法(不需要拦截校验)
登录校验调用
基于Redis实现共享session登录
在多机部署下,请求是随机地向某个服务器发送的,所以当进行一次登录时,session是存在对应的服务器上,登陆成功后执行其他请求方法,又是随机地向某个服务器发送请求,如果恰好该服务器上没有session,则发送请求失败
验证码由存入session改为存入redis,同时为了区分,采用phone作为key,
登录成功后手动生成一个token作为用户凭证(key)将登录用户存入redis中
则校验登录状态只需要根据token去redis获取用户即可,获取到且非空则放行,同时将用户存入ThreadLocal,使得后续可以随时获取用户信息(属性/字段)
发送验证码
验证码存入redis
校验验证码、注册
TODO:StringRedisTemplate只允许存入String类型的key、value,而userDTO中存在非String类型
最好把字符串login:token封装成枚举类常量LOGIN_USER_KEY
可以自己指定规则,将非String类型的转为String类型
修改登录校验拦截器
原先在MvcConfig配置类中配置拦截器时采用的new一个登录拦截器,而登录拦截器并没有使用@Component注解将登录拦截器交给SpringMVC,因此不能被SpringMVC注入想要的功能,即无法注入SpringRedisTemplate,所以只能使用构造方法
原先是从session中获取用户,现在使用token获取redis中的用户
修改拦截器配置
拦截器优化
存在的问题:假设我们现在做了一个token有效期的刷新,用户如果未操作,登录态最多保持30min,如果操作了(发送了某些请求),就需要刷新登录态,即刷新token的有效期,对于需要用户登录校验的方法,可以在校验成功后刷新token有效期,但对于不需要用户登录校验的方法(即被放行的方法),拦截器对它不生效,所以也就不进行登录校验并刷新token,导致对于这些方法,最多只能保持30min可操作时长
这个问题本质上是因为token有效期刷新和登录校验放在了同一个拦截器,而token有效期刷新是针对所有方法,登录校验只针对部分方法,那么我们只需要把token有效期刷新和登录校验分离开即可,因此可以设置两个拦截器
具体实现
刷新有效期就是再次设置过期时间
将用户信息存入线程池的操作在上面那个拦截器做了,所以这个拦截器不需要用到stringRedisTemplate操作redis去存用户信息到线程池
配置两个拦截器的优先顺序:order值越小的拦截器越优先