怎么使用Redis的共享session实现短信登录(redis,session,开发技术)

时间:2024-05-05 21:22:14 作者 : 石家庄SEO 分类 : 开发技术
  • TAG :

");
}
//3.符合,生成验证码(设置生成6位)
Stringcode=RandomUtil.randomNumbers(6);
//4.保存验证码到session
session.setAttribute("code",code);
//5.发送验证码(这里并未实现,通过日志记录)
log.debug("发送短信验证码成功,验证码:{}",code);
//返回ok
returnResult.ok();
}
}

1.3 实现短信验证码登录、注册

前端请求说明

说明请求方式POST请求路径/user/login请求参数phone(电话号码);code(验证码)返回值无

后端接口实现:

@Slf4j
@Service
publicclassUserServiceImplextendsServiceImpl<UserMapper,User>implementsIUserService{

@Override
publicResultlogin(LoginFormDTOloginForm,HttpSessionsession){
//1.校验手机号
Stringphone=loginForm.getPhone();
if(RegexUtils.isPhoneInvalid(phone)){
//不一致,返回错误信息
returnResult.fail("手机号格式错误!");
}
//2.校验验证码
StringcacheCode=(String)session.getAttribute("code");
Stringcode=loginForm.getCode();
if(cacheCode==null||!cacheCode.equals(cacheCode)){
//不一致,返回错误信息
returnResult.fail("验证码错误!");
}
//4.一致,根据手机号查询用户(这里使用的mybatis-plus)
Useruser=query().eq("phone",phone).one();
//5.判断用户是否存在
if(user==null){
//6.不存在,创建新用户并保存
user=createUserWithPhone(phone);
}
//7.保存用户信息到session中(通过BeanUtil.copyProperties方法将user中的信息过滤到UserDTO上,即用来隐藏部分信息)
session.setAttribute("user",BeanUtil.copyProperties(user,UserDTO.class));
returnResult.ok();
}

privateUsercreateUserWithPhone(Stringphone){
//1.创建用户
Useruser=newUser();
user.setPhone(phone);
user.setNickName("user_"+RandomUtil.randomString(10));
//2.保存用户(这里使用mybatis-plus)
save(user);
returnuser;
}
}

1.4 实现登录校验拦截器

登录校验拦截器实现:

publicclassLoginInterceptorimplementsHandlerInterceptor{
@Override
publicbooleanpreHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler)throwsException{
//1.获取session
HttpSessionsession=request.getSession();
//2.获取session中的用户
UserDTOuser=(UserDTO)session.getAttribute("user");
//3.判断用户是否存在
if(user==null){
//4.不存在,拦截,返回401未授权
response.setStatus(401);
returnfalse;
}
//5.存在,保存用户信息到ThreadLocal
UserHolder.saveUser(user);
//6.放行
returntrue;
}

@Override
publicvoidafterCompletion(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler,Exceptionex)throwsException{
//移除用户,避免内存泄露
UserHolder.removeUser();
}
}

UserHolder 类的实现: 该类中定义了一个静态的 ThreadLocal

publicclassUserHolder{
privatestaticfinalThreadLocal<UserDTO>tl=newThreadLocal<>();

publicstaticvoidsaveUser(UserDTOuser){
tl.set(user);
}

publicstaticUserDTOgetUser(){
returntl.get();
}

publicstaticvoidremoveUser(){
tl.remove();
}
}

配置拦截器:

@Configuration
publicclassMvcConfigimplementsWebMvcConfigurer{

@Override
publicvoidaddInterceptors(InterceptorRegistryregistry){
registry.addInterceptor(newLoginInterceptor())
.excludePathPatterns(
"/user/login",
"/user/code"
);
}
}

前端请求说明:

说明请求方式POST请求路径/user/me请求参数无返回值无

后端接口实现:

@Slf4j
@Service
publicclassUserServiceImplextendsServiceImpl<UserMapper,User>implementsIUserService{

@Override
publicResultme(){
UserDTOuser=UserHolder.getUser();
returnResult.ok(user);
}
}

2. 集群的 session 共享问题

session 共享问题:

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

session 的替代方案应该满足以下条件:

  • 数据共享(不同的 tomcat 都能够访问 Redis 中的数据)

  • 内存存储(Redis 通过内存存储)

  • key、value 结构(Redis 是 key-value 结构)

3. 基于 Redis 实现共享 session 登录

3.1 Redis 实现共享 session 登录流程图

怎么使用Redis的共享session实现短信登录

怎么使用Redis的共享session实现短信登录

3.2 实现发送短信验证码

前端请求说明:

说明请求方式POST请求路径/user/code请求参数phone(电话号码)返回值无

后端接口实现:

@Slf4j
@Service
publicclassUserServiceImplextendsServiceImpl<UserMapper,User>implementsIUserService{

@Resource
privateStringRedisTemplatestringRedisTemplate;

@Override
publicResultsendCode(Stringphone,HttpSessionsession){
//1.校验手机号
if(RegexUtils.isPhoneInvalid(phone)){
//2.如果不符合,返回错误信息
returnResult.fail("手机号格式错误!");
}
//3.符合,生成验证码(设置生成6位)
Stringcode=RandomUtil.randomNumbers(6);
//4.保存验证码到Redis(以手机号为key,设置有效期为2min)
stringRedisTemplate.opsForValue().set("login:code:"+phone,code,2,TimeUnit.MINUTES);
//5.发送验证码(这里并未实现,通过日志记录)
log.debug("发送短信验证码成功,验证码:{}",code);
//返回ok
returnResult.ok();
}
}

3.3 实现短信验证码登录、注册

前端请求说明:

说明请求方式POST请求路径/user/login请求参数phone(电话号码);code(验证码)返回值无

后端接口实现:

@Slf4j
@Service
publicclassUserServiceImplextendsServiceImpl<UserMapper,User>implementsIUserService{

@Override
publicResultlogin(LoginFormDTOloginForm,HttpSessionsession){
//1.校验手机号
Stringphone=loginForm.getPhone();
if(RegexUtils.isPhoneInvalid(phone)){
//不一致,返回错误信息
returnResult.fail("手机号格式错误!");
}
//2.校验验证码
StringcacheCode=(String)session.getAttribute("code");
Stringcode=loginForm.getCode();
if(cacheCode==null||!cacheCode.equals(cacheCode)){
//不一致,返回错误信息
returnResult.fail("验证码错误!");
}
//4.一致,根据手机号查询用户(这里使用的mybatis-plus)
Useruser=query().eq("phone",phone).one();
//5.判断用户是否存在
if(user==null){
//6.不存在,创建新用户并保存
user=createUserWithPhone(phone);
}
//7.保存用户信息到session中(通过BeanUtil.copyProperties方法将user中的信息过滤到UserDTO上,即用来隐藏部分信息)
session.setAttribute("user",BeanUtil.copyProperties(user,UserDTO.class));
returnResult.ok();
}

privateUsercreateUserWithPhone(Stringphone){
//1.创建用户
Useruser=newUser();
user.setPhone(phone);
user.setNickName("user_"+RandomUtil.randomString(10));
//2.保存用户(这里使用mybatis-plus)
save(user);
returnuser;
}
}

3.4 实现登录校验拦截器

这里将原有的一个拦截器分成两个拦截器,第一个拦截器对所有的请求进行拦截,每次拦截刷新 token 的有效期,并将能查询到的用户信息保存到 ThreadLocal 中。第二个拦截器则进行拦截功能,对需要登录的路径进行拦截。

刷新 token 拦截器实现:

publicclassRefreshTokenInterceptorimplementsHandlerInterceptor{

privateStringRedisTemplatestringRedisTemplate;

publicRefreshTokenInterceptor(StringRedisTemplatestringRedisTemplate){
this.stringRedisTemplate=stringRedisTemplate;
}

@Override
publicbooleanpreHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler)throwsException{
//1.获取请求头中的token
Stringtoken=request.getHeader("authorization");
if(StrUtil.isBlank(token)){
returntrue;
}
//2.基于token获取redis中的用户
StringtokenKey="login:token:"+token;
Map<Object,Object>userMap=stringRedisTemplate.opsForHash().entries(tokenKey);
//3.判断用户是否存在
if(userMap.isEmpty()){
returntrue;
}
//5.将查询到的Hash数据转为UserDTO对象
UserDTOuser=BeanUtil.fillBeanWithMap(userMap,newUserDTO(),false);
//6.存在,保存用户信息到ThreadLocal
UserHolder.saveUser(user);
//7.刷新token有效期30min
stringRedisTemplate.expire(tokenKey,30,TimeUnit.MINUTES);
//8.放行
returntrue;
}
}

登录校验拦截器实现:

publicclassLoginInterceptorimplementsHandlerInterceptor{
@Override
publicbooleanpreHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler)throwsException{
//1.获取session
HttpSessionsession=request.getSession();
//2.获取session中的用户
UserDTOuser=(UserDTO)session.getAttribute("user");
//3.判断用户是否存在
if(user==null){
//4.不存在,拦截,返回401未授权
response.setStatus(401);
returnfalse;
}
//5.存在,保存用户信息到ThreadLocal
UserHolder.saveUser(user);
//6.放行
returntrue;
}

@Override
publicvoidafterCompletion(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler,Exceptionex)throwsException{
//移除用户,避免内存泄露
UserHolder.removeUser();
}
}

UserHolder 类的实现: 该类中定义了一个静态的 ThreadLocal

publicclassUserHolder{
privatestaticfinalThreadLocal<UserDTO>tl=newThreadLocal<>();

publicstaticvoidsaveUser(UserDTOuser){
tl.set(user);
}

publicstaticUserDTOgetUser(){
returntl.get();
}

publicstaticvoidremoveUser(){
tl.remove();
}
}

配置拦截器:

@Configuration
publicclassMvcConfigimplementsWebMvcConfigurer{

@Resource
privateStringRedisTemplatestringRedisTemplate;

@Override
publicvoidaddInterceptors(InterceptorRegistryregistry){
registry.addInterceptor(newRefreshTokenInterceptor(stringRedisTemplate))
.addPathPatterns("/**").order(0);
registry.addInterceptor(newLoginInterceptor())
.excludePathPatterns(
"/user/login",
"/user/code"
).order(1);
}
}

前端请求说明:

说明请求方式POST请求路径/user/me请求参数无返回值无

后端接口实现:

@Slf4j
@Service
publicclassUserServiceImplextendsServiceImpl<UserMapper,User>implementsIUserService{

@Override
publicResultme(){
UserDTOuser=UserHolder.getUser();
returnResult.ok(user);
}
}

读到这里,这篇“怎么使用Redis的共享session实现短信登录”文章已经介绍完毕,想要掌握这篇文章的知识点还需要大家自己动手实践使用过才能领会,如果想了解更多相关内容的文章,欢迎关注亿速云行业资讯频道。

本文:怎么使用Redis的共享session实现短信登录的详细内容,希望对您有所帮助,信息来源于网络。
上一篇:maven使用过程中无法导入依赖怎么解决下一篇:

24 人围观 / 0 条评论 ↓快速评论↓

(必须)

(必须,保密)

阿狸1 阿狸2 阿狸3 阿狸4 阿狸5 阿狸6 阿狸7 阿狸8 阿狸9 阿狸10 阿狸11 阿狸12 阿狸13 阿狸14 阿狸15 阿狸16 阿狸17 阿狸18